diff options
author | nyamatongwe <unknown> | 2003-03-09 04:08:13 +0000 |
---|---|---|
committer | nyamatongwe <unknown> | 2003-03-09 04:08:13 +0000 |
commit | 0e5e6b976c968dce6e63eb68ecaabab35398ed24 (patch) | |
tree | b11df1d33c65b821e0eabb3c84a5503cefae7534 | |
parent | fc4ce601c44f0bc0ac7529d76597e482be9b97e4 (diff) | |
download | scintilla-mirror-0e5e6b976c968dce6e63eb68ecaabab35398ed24.tar.gz |
Added Pango text display support to GTK+ platform.
Added WindowID parameter to all Surface initialisation methods as Pango
requires a window to determine the context used for text functions.
AutoSurface changed because of above to take an Editor* argument so it
can then discover the code page and window.
-rw-r--r-- | gtk/PlatGTK.cxx | 551 | ||||
-rw-r--r-- | gtk/ScintillaGTK.cxx | 10 | ||||
-rw-r--r-- | include/Platform.h | 6 | ||||
-rw-r--r-- | src/CallTip.cxx | 2 | ||||
-rw-r--r-- | src/Editor.cxx | 36 | ||||
-rw-r--r-- | src/Editor.h | 75 | ||||
-rw-r--r-- | win32/PlatWin.cxx | 12 | ||||
-rw-r--r-- | win32/ScintillaWin.cxx | 14 |
8 files changed, 467 insertions, 239 deletions
diff --git a/gtk/PlatGTK.cxx b/gtk/PlatGTK.cxx index 0a84f46a1..073e51faa 100644 --- a/gtk/PlatGTK.cxx +++ b/gtk/PlatGTK.cxx @@ -7,6 +7,7 @@ #include <stdio.h> #include <stdlib.h> #include <stddef.h> +#define assert(c) ((c) ? (void)(0) : Platform::Assert(#c, __FILE__, __LINE__)) #include <glib.h> #include <gdk/gdk.h> @@ -34,11 +35,50 @@ #define snprintf _snprintf #endif +#if GTK_MAJOR_VERSION >= 2 +#define USE_PANGO 1 +#endif + #ifdef _MSC_VER // Ignore unreferenced local functions in GTK+ headers #pragma warning(disable: 4505) #endif +// On GTK+ 1.x holds a GdkFont* but on GTK+ 2.x can hold a GdkFont* or a +// PangoFontDescription*. +class FontHandle { +public: + int ascent; + GdkFont *pfont; +#ifdef USE_PANGO + PangoFontDescription *pfd; +#endif + FontHandle(GdkFont *pfont_) { + ascent = 0; + pfont = pfont_; +#ifdef USE_PANGO + pfd = 0; +#endif + } +#ifdef USE_PANGO + FontHandle(PangoFontDescription *pfd_) { + ascent = 0; + pfont = 0; + pfd = pfd_; + } +#endif + ~FontHandle() { + if (pfont) + gdk_font_unref(pfont); + pfont = 0; +#ifdef USE_PANGO + if (pfd) + pango_font_description_free(pfd); + pfd = 0; +#endif + } +}; + struct LOGFONT { int size; bool bold; @@ -94,8 +134,8 @@ static void FontMutexUnlock() { // X has a 16 bit coordinate space, so stop drawing here to avoid wrapping static const int maxCoordinate = 32000; -static GdkFont *PFont(Font &f) { - return reinterpret_cast<GdkFont *>(f.GetID()); +static FontHandle *PFont(Font &f) { + return reinterpret_cast<FontHandle *>(f.GetID()); } static GtkWidget *PWidget(WindowID id) { @@ -350,7 +390,7 @@ bool FontCached::SameAs(const char *faceName_, int characterSet_, int size_, boo void FontCached::Release() { if (id) - gdk_font_unref(PFont(*this)); + delete PFont(*this); id = 0; } @@ -396,7 +436,7 @@ void FontCached::ReleaseId(FontID id_) { FontMutexUnlock(); } -static FontID LoadFontOrSet(const char *fontspec, int characterSet) { +static GdkFont *LoadFontOrSet(const char *fontspec, int characterSet) { if (IsDBCSCharacterSet(characterSet)) { return gdk_fontset_load(fontspec); } else { @@ -416,8 +456,21 @@ FontID FontCached::CreateNewFont(const char *fontName, int characterSet, foundary[0] = '\0'; faceName[0] = '\0'; charset[0] = '\0'; - FontID newid = 0; +#ifdef USE_PANGO + if (fontName[0] == '!') { + PangoFontDescription *pfd = pango_font_description_new(); + if (pfd) { + pango_font_description_set_family(pfd, fontName+1); + pango_font_description_set_size(pfd, size * PANGO_SCALE); + pango_font_description_set_weight(pfd, bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL); + pango_font_description_set_style(pfd, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL); + return new FontHandle(pfd); + } + } +#endif + + GdkFont *newid = 0; // If name of the font begins with a '-', assume, that it is // a full fontspec. if (fontName[0] == '-') { @@ -432,7 +485,7 @@ FontID FontCached::CreateNewFont(const char *fontName, int characterSet, newid = LoadFontOrSet("-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-*", characterSet); } - return newid; + return new FontHandle(newid); } // it's not a full fontspec, build one. @@ -501,7 +554,7 @@ FontID FontCached::CreateNewFont(const char *fontName, int characterSet, newid = gdk_fontset_load(fontset); if (newid) - return newid; + return new FontHandle(newid); // if fontset load failed, fall through, we'll use // the last font entry and continue to try and @@ -550,7 +603,7 @@ FontID FontCached::CreateNewFont(const char *fontName, int characterSet, newid = LoadFontOrSet("-*-*-*-*-*-*-*-*-*-*-*-*-iso8859-*", characterSet); } - return newid; + return new FontHandle(newid); } Font::Font() : id(0) {} @@ -578,13 +631,17 @@ class SurfaceImpl : public Surface { int y; bool inited; bool createdGC; +#ifdef USE_PANGO + PangoContext *pcontext; + PangoLayout *layout; +#endif public: SurfaceImpl(); virtual ~SurfaceImpl(); - void Init(); - void Init(SurfaceID sid); - void InitPixMap(int width, int height, Surface *surface_); + void Init(WindowID wid); + void Init(SurfaceID sid, WindowID wid); + void InitPixMap(int width, int height, Surface *surface_, WindowID wid); void Release(); bool Initialised(); @@ -624,7 +681,11 @@ public: }; SurfaceImpl::SurfaceImpl() : unicodeMode(false), dbcsMode(false), drawable(0), gc(0), ppixmap(0), -x(0), y(0), inited(false), createdGC(false) { +x(0), y(0), inited(false), createdGC(false) +#ifdef USE_PANGO +, pcontext(0), layout(0) +#endif +{ } SurfaceImpl::~SurfaceImpl() { @@ -641,6 +702,14 @@ void SurfaceImpl::Release() { if (ppixmap) gdk_pixmap_unref(ppixmap); ppixmap = 0; +#ifdef USE_PANGO + if (layout) + g_object_unref(layout); + layout = 0; + if (pcontext) + g_object_unref(pcontext); + pcontext = 0; +#endif x = 0; y = 0; inited = false; @@ -651,30 +720,56 @@ bool SurfaceImpl::Initialised() { return inited; } -void SurfaceImpl::Init() { +// The WindowID argument is only used for Pango builds +#ifdef USE_PANGO +#define WID_NAME wid +#else +#define WID_NAME +#endif + +void SurfaceImpl::Init(WindowID WID_NAME) { + PLATFORM_ASSERT(wid); Release(); +#ifdef USE_PANGO + pcontext = gtk_widget_create_pango_context(PWidget(wid)); + PLATFORM_ASSERT(pcontext); + layout = pango_layout_new(pcontext); + PLATFORM_ASSERT(layout); +#endif inited = true; } -void SurfaceImpl::Init(SurfaceID sid) { +void SurfaceImpl::Init(SurfaceID sid, WindowID WID_NAME) { + PLATFORM_ASSERT(wid); + PLATFORM_ASSERT(sid); GdkDrawable *drawable_ = reinterpret_cast<GdkDrawable *>(sid); Release(); +#ifdef USE_PANGO + pcontext = gtk_widget_create_pango_context(PWidget(wid)); + layout = pango_layout_new(pcontext); +#endif drawable = drawable_; gc = gdk_gc_new(drawable_); - //gdk_gc_set_line_attributes(gc, 1, - // GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_BEVEL); createdGC = true; inited = true; } -void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_) { +void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID WID_NAME) { + PLATFORM_ASSERT(wid); + PLATFORM_ASSERT(surface_); Release(); + SurfaceImpl *surfImpl = static_cast<SurfaceImpl *>(surface_); + PLATFORM_ASSERT(surfImpl->drawable); +#ifdef USE_PANGO + pcontext = gtk_widget_create_pango_context(PWidget(wid)); + PLATFORM_ASSERT(pcontext); + layout = pango_layout_new(pcontext); + PLATFORM_ASSERT(layout); +#endif if (height > 0 && width > 0) - ppixmap = gdk_pixmap_new(static_cast<SurfaceImpl *>(surface_)->drawable, width, height, -1); + ppixmap = gdk_pixmap_new(surfImpl->drawable, width, height, -1); drawable = ppixmap; - gc = gdk_gc_new(static_cast<SurfaceImpl *>(surface_)->drawable); - //gdk_gc_set_line_attributes(gc, 1, - // GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_BEVEL); + gc = gdk_gc_new(surfImpl->drawable); createdGC = true; inited = true; } @@ -821,77 +916,142 @@ void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) { } } -#define MAX_US_LEN 5000 +static size_t UTF8Len(char ch) { + unsigned char uch = static_cast<unsigned char>(ch); + if (uch < 0x80) + return 1; + else if (uch < (0x80 + 0x40 + 0x20)) + return 2; + else + return 3; +} + +#ifdef USE_PANGO + +static char *UTF8FromLatin1(const char *s, int len) { + char *utfForm = new char[len*2+1]; + size_t lenU = 0; + for (int i=0;i<len;i++) { + unsigned int uch = static_cast<unsigned char>(s[i]); + if (uch < 0x80) { + utfForm[lenU++] = uch; + } else { + utfForm[lenU++] = static_cast<char>(0xC0 | (uch >> 6)); + utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f)); + } + } + utfForm[lenU] = '\0'; + return utfForm; +} + +static char *UTF8FromGdkWChar(GdkWChar *wctext, int wclen) { + char *utfForm = new char[wclen*3+1]; // Maximum of 3 UTF-8 bytes per character + size_t lenU = 0; + for (int i = 0; i < wclen && wctext[i]; i++) { + unsigned int uch = wctext[i]; + if (uch < 0x80) { + utfForm[lenU++] = static_cast<char>(uch); + } else if (uch < 0x800) { + utfForm[lenU++] = static_cast<char>(0xC0 | (uch >> 6)); + utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f)); + } else { + utfForm[lenU++] = static_cast<char>(0xE0 | (uch >> 12)); + utfForm[lenU++] = static_cast<char>(0x80 | ((uch >> 6) & 0x3f)); + utfForm[lenU++] = static_cast<char>(0x80 | (uch & 0x3f)); + } + } + utfForm[lenU] = '\0'; + return utfForm; +} + +static char *UTF8FromDBCS(const char *s, int len) { + GdkWChar *wctext = new GdkWChar[len + 1]; + GdkWChar *wcp = wctext; + int wclen = gdk_mbstowcs(wcp, s, len); + if (wclen < 1) { + // In the annoying case when non-locale chars in the line. + // e.g. latin1 chars in Japanese locale. + delete []wctext; + return 0; + } + + char *utfForm = UTF8FromGdkWChar(wctext, wclen); + delete []wctext; + return utfForm; +} + +#endif + +// On GTK+, wchar_t is 4 bytes + +const int maxLengthTextRun = 10000; void SurfaceImpl::DrawTextBase(PRectangle rc, Font &font_, int ybase, const char *s, int len, ColourAllocated fore) { PenColour(fore); if (gc && drawable) { - // Draw text as a series of segments to avoid limitations in X servers - const int segmentLength = 1000; int x = rc.left; - if (unicodeMode) { - GdkWChar wctext[MAX_US_LEN]; - GdkWChar *wcp = (GdkWChar *) & wctext; - size_t wclen = UCS2FromUTF8(s, len, (wchar_t *)wctext, - sizeof(wctext) / sizeof(GdkWChar) - 1); - wctext[wclen] = L'\0'; - int lenDraw; - while ((wclen > 0) && (x < maxCoordinate)) { - lenDraw = Platform::Minimum(wclen, segmentLength); - gdk_draw_text_wc(drawable, PFont(font_), gc, - x, ybase, wcp, lenDraw); - wclen -= lenDraw; - if (wclen > 0) { - x += gdk_text_width_wc(PFont(font_), - wcp, lenDraw); +#ifdef USE_PANGO + if (PFont(font_)->pfd) { + char *utfForm = 0; + if (unicodeMode) { + pango_layout_set_text(layout, s, len); + } else { + if (dbcsMode) { + // Convert to utf8 + utfForm = UTF8FromDBCS(s, len); } - wcp += lenDraw; + if (!utfForm) // Latin1 or DBCS failed so treat as Latin1 + utfForm = UTF8FromLatin1(s, len); + pango_layout_set_text(layout, utfForm, strlen(utfForm)); } - } else if (dbcsMode) { - GdkWChar wctext[MAX_US_LEN]; - GdkWChar *wcp = (GdkWChar *) & wctext; - int wclen = gdk_mbstowcs(wcp, s, MAX_US_LEN); - - /* In the annoying case when non-locale chars - * in the line. - * e.g. latin1 chars in Japanese locale */ - if (wclen < 1) { - while ((len > 0) && (x < maxCoordinate)) { - int lenDraw = Platform::Minimum(len, segmentLength); - gdk_draw_text(drawable, PFont(font_), gc, - x, ybase, s, lenDraw); - len -= lenDraw; - if (len > 0) { - x += gdk_text_width(PFont(font_), s, lenDraw); - } - s += lenDraw; - } - } else { + pango_layout_set_font_description(layout, PFont(font_)->pfd); + PangoLayoutLine *pll = pango_layout_get_line(layout,0); + gdk_draw_layout_line(drawable, gc, x, ybase, pll); + delete []utfForm; + return; + } +#endif + // Draw text as a series of segments to avoid limitations in X servers + const int segmentLength = 1000; + bool draw8bit = true; + if (unicodeMode || dbcsMode) { + GdkWChar wctext[maxLengthTextRun]; + int wclen; + if (unicodeMode) { + wclen = UCS2FromUTF8(s, len, + reinterpret_cast<wchar_t *>(wctext), maxLengthTextRun - 1); + } else { // dbcsMode, so convert using current locale + wclen = gdk_mbstowcs( + wctext, s, maxLengthTextRun - 1); + } + if (wclen > 0) { + draw8bit = false; wctext[wclen] = L'\0'; - int lenDraw; + GdkWChar *wcp = wctext; while ((wclen > 0) && (x < maxCoordinate)) { - lenDraw = Platform::Minimum(wclen, segmentLength); - gdk_draw_text_wc(drawable, PFont(font_), gc, - x, ybase, wcp, lenDraw); + int lenDraw = Platform::Minimum(wclen, segmentLength); + gdk_draw_text_wc(drawable, PFont(font_)->pfont, gc, + x, ybase, wcp, lenDraw); wclen -= lenDraw; - if (wclen > 0) { - x += gdk_text_width_wc(PFont(font_), - wcp, lenDraw); - } wcp += lenDraw; - } + if (wclen > 0) { // Avoid next calculation if possible as may be expensive + x += gdk_text_width_wc(PFont(font_)->pfont, + wcp, lenDraw); + } + } } - } else { + } + if (draw8bit) { while ((len > 0) && (x < maxCoordinate)) { int lenDraw = Platform::Minimum(len, segmentLength); - gdk_draw_text(drawable, PFont(font_), gc, + gdk_draw_text(drawable, PFont(font_)->pfont, gc, x, ybase, s, lenDraw); len -= lenDraw; - if (len > 0) { - x += gdk_text_width(PFont(font_), s, lenDraw); - } s += lenDraw; + if (len > 0) { // Avoid next calculation if possible as may be expensive + x += gdk_text_width(PFont(font_)->pfont, s, lenDraw); + } } } } @@ -919,86 +1079,98 @@ void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, con void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) { if (font_.GetID()) { int totalWidth = 0; - GdkFont *gf = PFont(font_); - if (unicodeMode) { - GdkWChar wctext[MAX_US_LEN]; - size_t wclen = UCS2FromUTF8(s, len, (wchar_t *)wctext, sizeof(wctext) / sizeof(GdkWChar) - 1); - wctext[wclen] = L'\0'; - int poses[MAX_US_LEN]; - size_t i; - for (i = 0; i < wclen; i++) { - int width = gdk_char_width_wc(gf, wctext[i]); - totalWidth += width; - poses[i] = totalWidth; - } - // map widths back to utf-8 input string - size_t ui = 0; - i = 0; - const unsigned char *us = reinterpret_cast<const unsigned char *>(s); - unsigned char uch; - while (ui < wclen) { - 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]; +#ifdef USE_PANGO + if (PFont(font_)->pfd) { + PangoRectangle pos; + pango_layout_set_font_description(layout, PFont(font_)->pfd); + if (unicodeMode) { + // Simple and direct as UTF-8 is native Pango encoding + pango_layout_set_text(layout, s, len); + int i = 0; + while (i < len) { + pango_layout_index_to_pos(layout, i+1, &pos); + positions[i++] = PANGO_PIXELS(pos.x); + } + } else { + int wclen = 0; + if (dbcsMode) { + GdkWChar *wctext = new GdkWChar[len + 1]; + GdkWChar *wcp = wctext; + wclen = gdk_mbstowcs(wcp, s, len); + if (wclen >= 1 ) { + // Convert to UTF-8 so can ask Pango for widths, then + // Loop through UTF-8 and DBCS forms, taking account of different + // character byte lengths. + char *utfForm = UTF8FromGdkWChar(wctext, wclen); + pango_layout_set_text(layout, utfForm, strlen(utfForm)); + int i = 0; + int iU = 0; + while (i < len) { + pango_layout_index_to_pos(layout, iU+1, &pos); + iU += UTF8Len(utfForm[iU]); + size_t lenChar = mblen(s+i, MB_CUR_MAX); + while (lenChar--) { + positions[i++] = PANGO_PIXELS(pos.x); + } + } + delete []utfForm; } + delete []wctext; + } + if (wclen < 1 ) { + // Either Latin1 or DBCS conversion failed so treat as Latin1. + char *utfForm = UTF8FromLatin1(s, len); + pango_layout_set_text(layout, utfForm, strlen(utfForm)); + int i = 0; + int iU = 0; + while (i < len) { + pango_layout_index_to_pos(layout, iU+1, &pos); + iU += UTF8Len(s[i]); + positions[i++] = PANGO_PIXELS(pos.x); + } + delete []utfForm; } - ui++; } - int lastPos = 0; - if (i > 0) - lastPos = positions[i - 1]; - while (i < static_cast<size_t>(len)) { - positions[i++] = lastPos; + return; + } +#endif + GdkFont *gf = PFont(font_)->pfont; + bool measure8bit = true; + if (unicodeMode || dbcsMode) { + GdkWChar wctext[maxLengthTextRun]; + int wclen; + if (unicodeMode) { + wclen = UCS2FromUTF8(s, len, + reinterpret_cast<wchar_t *>(wctext), maxLengthTextRun - 1); + } else { // dbcsMode, so convert using current locale + wclen = gdk_mbstowcs( + wctext, s, maxLengthTextRun - 1); } - } else if (dbcsMode) { - GdkWChar wctext[MAX_US_LEN]; - size_t wclen = (size_t)gdk_mbstowcs(wctext, s, MAX_US_LEN); - /* In the annoying case when non-locale chars - * in the line. - * e.g. latin1 chars in Japanese locale */ - if( (int)wclen < 1 ) { - for (int i = 0; i < len; i++) { - int width = gdk_char_width(gf, s[i]); - totalWidth += width; - positions[i] = totalWidth; - } - } else { + if (wclen > 0) { + measure8bit = false; wctext[wclen] = L'\0'; - int poses[MAX_US_LEN]; - size_t i; - for (i = 0; i < wclen; i++) { - int width = gdk_char_width_wc(gf, wctext[i]); + // Map widths back to utf-8 or DBCS input string + int i = 0; + for (int iU = 0; iU < wclen; iU++) { + int width = gdk_char_width_wc(gf, wctext[iU]); totalWidth += width; - poses[i] = totalWidth; - } - size_t ui = 0; - i = 0; - for (ui = 0; ui< wclen; ui++) { - GdkWChar wch[2]; - wch[0] = wctext[ui]; - wch[1] = L'\0'; - gchar* mbstr = gdk_wcstombs(wch); - if (mbstr == NULL || *mbstr == '\0') - g_error("mbs broken\n"); - for(int j=0; j<(int)strlen(mbstr); j++) { - positions[i++] = poses[ui]; + size_t lenChar; + if (unicodeMode) { + lenChar = UTF8Len(s[i]); + } else { + lenChar = mblen(s+i, MB_CUR_MAX); + } + while (lenChar--) { + positions[i++] = totalWidth; } - if( mbstr != NULL ) - g_free(mbstr); } - int lastPos = 0; - if (i > 0) - lastPos = positions[i - 1]; - while (i < static_cast<size_t>(len)) { - positions[i++] = lastPos; + while (i < len) { // In case of problems with lengths + positions[i++] = totalWidth; } } - } else { + } + if (measure8bit) { + // Either Latin1 or conversion failed so treat as Latin1. for (int i = 0; i < len; i++) { int width = gdk_char_width(gf, s[i]); totalWidth += width; @@ -1006,6 +1178,7 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi } } } else { + // No font so return an ascending range of values for (int i = 0; i < len; i++) { positions[i] = i + 1; } @@ -1014,24 +1187,52 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi int SurfaceImpl::WidthText(Font &font_, const char *s, int len) { if (font_.GetID()) { +#ifdef USE_PANGO + if (PFont(font_)->pfd) { + char *utfForm = 0; + pango_layout_set_font_description(layout, PFont(font_)->pfd); + PangoRectangle pos; + if (unicodeMode) { + pango_layout_set_text(layout, s, len); + } else { + if (dbcsMode) { + // Convert to utf8 + utfForm = UTF8FromDBCS(s, len); + } + if (!utfForm) // Latin1 or DBCS failed so treat as Latin1 + utfForm = UTF8FromLatin1(s, len); + pango_layout_set_text(layout, utfForm, strlen(utfForm)); + } + pango_layout_index_to_pos(layout, len, &pos); + int width = PANGO_PIXELS(pos.x); + delete []utfForm; + return width; + } +#endif if (unicodeMode) { - GdkWChar wctext[MAX_US_LEN]; + GdkWChar wctext[maxLengthTextRun]; size_t wclen = UCS2FromUTF8(s, len, (wchar_t *)wctext, sizeof(wctext) / sizeof(GdkWChar) - 1); wctext[wclen] = L'\0'; - int width = gdk_text_width_wc(PFont(font_), wctext, wclen); - return width; - } else - return gdk_text_width(PFont(font_), s, len); + return gdk_text_width_wc(PFont(font_)->pfont, wctext, wclen); + } else { + return gdk_text_width(PFont(font_)->pfont, s, len); + } } else { return 1; } } int SurfaceImpl::WidthChar(Font &font_, char ch) { - if (font_.GetID()) - return gdk_char_width(PFont(font_), ch); - else + if (font_.GetID()) { +#ifdef USE_PANGO + if (PFont(font_)->pfd) { + return WidthText(font_, &ch, 1); + } +#endif + return gdk_char_width(PFont(font_)->pfont, ch); + } else { return 1; + } } // Three possible strategies for determining ascent and descent of font: @@ -1050,11 +1251,23 @@ const char sizeString[] = "`~!@#$%^&*()-_=+\\|[]{};:\"\'<,>.?/1234567890" "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; int SurfaceImpl::Ascent(Font &font_) { - if (!font_.GetID()) + if (!(font_.GetID())) return 1; #ifdef FAST_WAY + if (PFont(font_)->ascent > 0) + return PFont(font_)->ascent; +#ifdef USE_PANGO + if (PFont(font_)->pfd) { + PangoFontMetrics *metrics = pango_context_get_metrics(pcontext, + PFont(font_)->pfd, pango_context_get_language(pcontext)); + PFont(font_)->ascent = + PANGO_PIXELS(pango_font_metrics_get_ascent(metrics)); + pango_font_metrics_unref(metrics); + return PFont(font_)->ascent; + } +#endif - return PFont(font_)->ascent; + return PFont(font_)->pfont->ascent; #else gint lbearing; @@ -1063,18 +1276,27 @@ int SurfaceImpl::Ascent(Font &font_) { gint ascent; gint descent; - gdk_string_extents(PFont(font_), sizeString, + gdk_string_extents(PFont(font_)->pfont, sizeString, &lbearing, &rbearing, &width, &ascent, &descent); return ascent; #endif } int SurfaceImpl::Descent(Font &font_) { - if (!font_.GetID()) + if (!(font_.GetID())) return 1; #ifdef FAST_WAY - return PFont(font_)->descent; +#ifdef USE_PANGO + if (PFont(font_)->pfd) { + PangoFontMetrics *metrics = pango_context_get_metrics(pcontext, + PFont(font_)->pfd, pango_context_get_language(pcontext)); + int descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics)); + pango_font_metrics_unref(metrics); + return descent; + } +#endif + return PFont(font_)->pfont->descent; #else gint lbearing; @@ -1083,7 +1305,7 @@ int SurfaceImpl::Descent(Font &font_) { gint ascent; gint descent; - gdk_string_extents(PFont(font_), sizeString, + gdk_string_extents(PFont(font_)->pfont, sizeString, &lbearing, &rbearing, &width, &ascent, &descent); return descent; #endif @@ -1102,10 +1324,7 @@ int SurfaceImpl::Height(Font &font_) { } int SurfaceImpl::AverageCharWidth(Font &font_) { - if (font_.GetID()) - return gdk_char_width(PFont(font_), 'n'); - else - return 1; + return WidthChar(font_, 'n'); } int SurfaceImpl::SetPalette(Palette *, bool) { @@ -1381,10 +1600,10 @@ void ListBoxX::Create(Window &, int, int, bool) { void ListBoxX::SetFont(Font &scint_font) { #if GTK_MAJOR_VERSION < 2 GtkStyle *style = gtk_widget_get_style(GTK_WIDGET(PWidget(list))); - if (!gdk_font_equal(style->font, PFont(scint_font))) { + if (!gdk_font_equal(style->font, PFont(scint_font)->pfont)) { style = gtk_style_copy(style); gdk_font_unref(style->font); - style->font = PFont(scint_font); + style->font = PFont(scint_font)->pfont; gdk_font_ref(style->font); gtk_widget_set_style(GTK_WIDGET(PWidget(list)), style); gtk_style_unref(style); @@ -1392,9 +1611,9 @@ void ListBoxX::SetFont(Font &scint_font) { #else GtkStyle *styleCurrent = gtk_widget_get_style(GTK_WIDGET(PWidget(list))); GdkFont *fontCurrent = gtk_style_get_font(styleCurrent); - if (!gdk_font_equal(fontCurrent, PFont(scint_font))) { + if (!gdk_font_equal(fontCurrent, PFont(scint_font)->pfont)) { GtkStyle *styleNew = gtk_style_copy(styleCurrent); - gtk_style_set_font(styleNew, PFont(scint_font)); + gtk_style_set_font(styleNew, PFont(scint_font)->pfont); gtk_widget_set_style(GTK_WIDGET(PWidget(list)), styleNew); gtk_style_unref(styleCurrent); } diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx index 7a2bfa458..e0fd95a99 100644 --- a/gtk/ScintillaGTK.cxx +++ b/gtk/ScintillaGTK.cxx @@ -93,7 +93,7 @@ class ScintillaGTK : public ScintillaBase { gint wheelMouseIntensity; // Private so ScintillaGTK objects can not be copied -ScintillaGTK(const ScintillaGTK &) : ScintillaBase() {} + ScintillaGTK(const ScintillaGTK &) : ScintillaBase() {} ScintillaGTK &operator=(const ScintillaGTK &) { return * this; } public: @@ -654,7 +654,7 @@ void ScintillaGTK::FullPaint() { if ((PWidget(wMain))->window) { Surface *sw = Surface::Allocate(); if (sw) { - sw->Init((PWidget(wMain))->window); + sw->Init(PWidget(wMain)->window, PWidget(wMain)); Paint(sw, rcPaint); sw->Release(); delete sw; @@ -691,7 +691,7 @@ void ScintillaGTK::SyncPaint(PRectangle rc) { if ((PWidget(wMain))->window) { Surface *sw = Surface::Allocate(); if (sw) { - sw->Init((PWidget(wMain))->window); + sw->Init(PWidget(wMain)->window, PWidget(wMain)); Paint(sw, rc); sw->Release(); delete sw; @@ -1520,7 +1520,7 @@ gint ScintillaGTK::Expose(GtkWidget *, GdkEventExpose *ose) { paintingAllText = rcPaint.Contains(rcClient); Surface *surfaceWindow = Surface::Allocate(); if (surfaceWindow) { - surfaceWindow->Init((PWidget(wMain))->window); + surfaceWindow->Init(PWidget(wMain)->window, PWidget(wMain)); // Fill the corner between the scrollbars PRectangle rcCorner = wMain.GetClientPosition(); if (verticalScrollBarVisible) @@ -1668,7 +1668,7 @@ void ScintillaGTK::PopUpCB(ScintillaGTK *sciThis, guint action, GtkWidget *) { gint ScintillaGTK::ExposeCT(GtkWidget *widget, GdkEventExpose * /*ose*/, CallTip *ctip) { Surface *surfaceWindow = Surface::Allocate(); if (surfaceWindow) { - surfaceWindow->Init(widget->window); + surfaceWindow->Init(widget->window, widget); ctip->PaintCT(surfaceWindow); surfaceWindow->Release(); delete surfaceWindow; diff --git a/include/Platform.h b/include/Platform.h index ee6e07c34..fa3c9ea10 100644 --- a/include/Platform.h +++ b/include/Platform.h @@ -293,9 +293,9 @@ public: virtual ~Surface() {}; static Surface *Allocate(); - virtual void Init()=0; - virtual void Init(SurfaceID sid)=0; - virtual void InitPixMap(int width, int height, Surface *surface_)=0; + virtual void Init(WindowID wid)=0; + virtual void Init(SurfaceID sid, WindowID wid)=0; + virtual void InitPixMap(int width, int height, Surface *surface_, WindowID wid)=0; virtual void Release()=0; virtual bool Initialised()=0; diff --git a/src/CallTip.cxx b/src/CallTip.cxx index f95a1db14..c83e2d2fd 100644 --- a/src/CallTip.cxx +++ b/src/CallTip.cxx @@ -129,7 +129,7 @@ PRectangle CallTip::CallTipStart(int pos, Point pt, const char *defn, Surface *surfaceMeasure = Surface::Allocate(); if (!surfaceMeasure) return PRectangle(); - surfaceMeasure->Init(); + surfaceMeasure->Init(wCallTip.GetID()); surfaceMeasure->SetUnicodeMode(SC_CP_UTF8 == codePage); surfaceMeasure->SetDBCSMode(codePage); startHighlight = 0; diff --git a/src/Editor.cxx b/src/Editor.cxx index 7569d5a60..643c8eee4 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -420,7 +420,7 @@ void Editor::RefreshColourPalette(Palette &pal, bool want) { void Editor::RefreshStyleData() { if (!stylesValid) { stylesValid = true; - AutoSurface surface(CodePage()); + AutoSurface surface(this); if (surface) { vs.Refresh(*surface); RefreshColourPalette(palette, true); @@ -523,7 +523,7 @@ Point Editor::LocationFromPosition(int pos) { int line = pdoc->LineFromPosition(pos); int lineVisible = cs.DisplayFromDoc(line); //Platform::DebugPrintf("line=%d\n", line); - AutoSurface surface(CodePage()); + AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(line)); if (surface && ll) { // -1 because of adding in for visible lines in following loop. @@ -581,7 +581,7 @@ int Editor::PositionFromLocation(Point pt) { return pdoc->Length(); unsigned int posLineStart = pdoc->LineStart(lineDoc); int retVal = posLineStart; - AutoSurface surface(CodePage()); + AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); if (surface && ll) { LayoutLine(lineDoc, surface, vs, ll, wrapWidth); @@ -624,7 +624,7 @@ int Editor::PositionFromLocationClose(Point pt) { return INVALID_POSITION; if (lineDoc >= pdoc->LinesTotal()) return INVALID_POSITION; - AutoSurface surface(CodePage()); + AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); if (surface && ll) { LayoutLine(lineDoc, surface, vs, ll, wrapWidth); @@ -656,7 +656,7 @@ int Editor::PositionFromLineX(int lineDoc, int x) { if (lineDoc >= pdoc->LinesTotal()) return pdoc->Length(); //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); - AutoSurface surface(CodePage()); + AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); int retVal = 0; if (surface && ll) { @@ -983,7 +983,7 @@ void Editor::MoveCaretInsideView(bool ensureVisible) { int Editor::DisplayFromPosition(int pos) { int lineDoc = pdoc->LineFromPosition(pos); int lineDisplay = cs.DisplayFromDoc(lineDoc); - AutoSurface surface(CodePage()); + AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); if (surface && ll) { LayoutLine(lineDoc, surface, vs, ll, wrapWidth); @@ -1327,7 +1327,7 @@ bool Editor::WrapLines() { wrapWidth = rcTextArea.Width(); // Ensure all of the document is styled. pdoc->EnsureStyledTo(pdoc->Length()); - AutoSurface surface(CodePage()); + AutoSurface surface(this); if (surface) { int lastLineToWrap = pdoc->LinesTotal(); while (docLineLastWrapped <= lastLineToWrap) { @@ -1394,7 +1394,7 @@ void Editor::LinesSplit(int pixelWidth) { const char *eol = StringFromEOLMode(pdoc->eolMode); pdoc->BeginUndoAction(); for (int line = lineStart; line <= lineEnd; line++) { - AutoSurface surface(CodePage()); + AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(line)); if (surface && ll) { unsigned int posLineStart = pdoc->LineStart(line); @@ -2214,7 +2214,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis void Editor::RefreshPixMaps(Surface *surfaceWindow) { if (!pixmapSelPattern->Initialised()) { const int patternSize=8; - pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow); + pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID()); // This complex procedure is to reproduce the checkerboard dithered pattern used by windows // for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half // way between the chrome colour and the chrome highlight colour making a nice transition @@ -2251,8 +2251,8 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) { if (!pixmapIndentGuide->Initialised()) { // 1 extra pixel in height so can handle odd/even positions and so produce a continuous line - pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow); - pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow); + pixmapIndentGuide->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID()); + pixmapIndentGuideHighlight->InitPixMap(1, vs.lineHeight + 1, surfaceWindow, wMain.GetID()); PRectangle rcIG(0, 0, 1, vs.lineHeight); pixmapIndentGuide->FillRectangle(rcIG, vs.styles[STYLE_INDENTGUIDE].back.allocated); pixmapIndentGuide->PenColour(vs.styles[STYLE_INDENTGUIDE].fore.allocated); @@ -2270,9 +2270,9 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) { if (!pixmapLine->Initialised()) { PRectangle rcClient = GetClientRectangle(); pixmapLine->InitPixMap(rcClient.Width(), rcClient.Height(), - surfaceWindow); + surfaceWindow, wMain.GetID()); pixmapSelMargin->InitPixMap(vs.fixedColumnWidth, - rcClient.Height(), surfaceWindow); + rcClient.Height(), surfaceWindow, wMain.GetID()); } } } @@ -2583,10 +2583,10 @@ long Editor::FormatRange(bool draw, RangeToFormat *pfr) { if (!pfr) return 0; - AutoSurface surface(pfr->hdc, CodePage()); + AutoSurface surface(pfr->hdc, this); if (!surface) return 0; - AutoSurface surfaceMeasure(pfr->hdcTarget, CodePage()); + AutoSurface surfaceMeasure(pfr->hdcTarget, this); if (!surfaceMeasure) { return 0; } @@ -2758,7 +2758,7 @@ long Editor::FormatRange(bool draw, RangeToFormat *pfr) { int Editor::TextWidth(int style, const char *text) { RefreshStyleData(); - AutoSurface surface(CodePage()); + AutoSurface surface(this); if (surface) { return surface->WidthText(vs.styles[style].font, text, strlen(text)); } else { @@ -3169,7 +3169,7 @@ void Editor::CheckModificationForWrap(DocModification mh) { if (wrapState != eWrapNone) { int lineDoc = pdoc->LineFromPosition(mh.position); if (mh.linesAdded == 0) { - AutoSurface surface(CodePage()); + AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); if (surface && ll) { LayoutLine(lineDoc, surface, vs, ll, wrapWidth); @@ -3537,7 +3537,7 @@ void Editor::CursorUpOrDown(int direction, bool extend) { int Editor::StartEndDisplayLine(int pos, bool start) { RefreshStyleData(); int line = pdoc->LineFromPosition(pos); - AutoSurface surface(CodePage()); + AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(line)); int posRet = INVALID_POSITION; if (surface && ll) { diff --git a/src/Editor.h b/src/Editor.h index 5db0e870d..d7582111d 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -132,40 +132,6 @@ public: }; /** - * A smart pointer class to ensure Surfaces are set up and deleted correctly. - */ -class AutoSurface { -private: - Surface *surf; -public: - AutoSurface(int codePage) { - surf = Surface::Allocate(); - if (surf) { - surf->Init(); - surf->SetUnicodeMode(SC_CP_UTF8 == codePage); - surf->SetDBCSMode(codePage); - } - } - AutoSurface(SurfaceID sid, int codePage) { - surf = Surface::Allocate(); - if (surf) { - surf->Init(sid); - surf->SetUnicodeMode(SC_CP_UTF8 == codePage); - surf->SetDBCSMode(codePage); - } - } - ~AutoSurface() { - delete surf; - } - Surface *operator->() const { - return surf; - } - operator Surface *() const { - return surf; - } -}; - -/** */ class Editor : public DocWatcher { // Private so Editor objects can not be copied @@ -362,7 +328,7 @@ protected: // ScintillaBase subclass needs access to much of Editor bool overrideBackground, ColourAllocated background); void DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart, PRectangle rcLine, LineLayout *ll, int subLine=0); - void RefreshPixMaps(Surface *surfaceWindow); + void RefreshPixMaps(Surface *surfaceWindow); void Paint(Surface *surfaceWindow, PRectangle rcArea); long FormatRange(bool draw, RangeToFormat *pfr); int TextWidth(int style, const char *text); @@ -485,6 +451,45 @@ public: virtual sptr_t WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam); // Public so scintilla_set_id can use it. int ctrlID; + friend class AutoSurface; +}; + +/** + * A smart pointer class to ensure Surfaces are set up and deleted correctly. + */ +class AutoSurface { +private: + Surface *surf; +public: + AutoSurface(Editor *ed) : surf(0) { + if (ed->wMain.GetID()) { + surf = Surface::Allocate(); + if (surf) { + surf->Init(ed->wMain.GetID()); + surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage()); + surf->SetDBCSMode(ed->CodePage()); + } + } + } + AutoSurface(SurfaceID sid, Editor *ed) : surf(0) { + if (ed->wMain.GetID()) { + surf = Surface::Allocate(); + if (surf) { + surf->Init(sid, ed->wMain.GetID()); + surf->SetUnicodeMode(SC_CP_UTF8 == ed->CodePage()); + surf->SetDBCSMode(ed->CodePage()); + } + } + } + ~AutoSurface() { + delete surf; + } + Surface *operator->() const { + return surf; + } + operator Surface *() const { + return surf; + } }; #endif diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx index 80a2e8557..23c7862ed 100644 --- a/win32/PlatWin.cxx +++ b/win32/PlatWin.cxx @@ -292,9 +292,9 @@ public: SurfaceImpl(); virtual ~SurfaceImpl(); - void Init(); - void Init(SurfaceID sid); - void InitPixMap(int width, int height, Surface *surface_); + void Init(WindowID wid); + void Init(SurfaceID sid, WindowID wid); + void InitPixMap(int width, int height, Surface *surface_, WindowID wid); void Release(); bool Initialised(); @@ -390,20 +390,20 @@ bool SurfaceImpl::Initialised() { return hdc != 0; } -void SurfaceImpl::Init() { +void SurfaceImpl::Init(WindowID) { Release(); hdc = ::CreateCompatibleDC(NULL); hdcOwned = true; ::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); } -void SurfaceImpl::Init(SurfaceID sid) { +void SurfaceImpl::Init(SurfaceID sid, WindowID) { Release(); hdc = reinterpret_cast<HDC>(sid); ::SetTextAlign(reinterpret_cast<HDC>(hdc), TA_BASELINE); } -void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_) { +void SurfaceImpl::InitPixMap(int width, int height, Surface *surface_, WindowID) { Release(); hdc = ::CreateCompatibleDC(static_cast<SurfaceImpl *>(surface_)->hdc); hdcOwned = true; diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index b303db27a..1ac55315f 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -384,7 +384,7 @@ LRESULT ScintillaWin::WndPaint(uptr_t wParam) { pps = &ps; ::BeginPaint(MainHWND(), pps); } - AutoSurface surfaceWindow(pps->hdc, CodePage()); + AutoSurface surfaceWindow(pps->hdc, this); if (surfaceWindow) { rcPaint = PRectangle(pps->rcPaint.left, pps->rcPaint.top, pps->rcPaint.right, pps->rcPaint.bottom); PRectangle rcClient = GetClientRectangle(); @@ -1428,7 +1428,7 @@ void ScintillaWin::ImeStartComposition() { int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel; if (sizeZoomed <= 2) // Hangs if sizeZoomed <= 1 sizeZoomed = 2; - AutoSurface surface(CodePage()); + AutoSurface surface(this); int deviceHeight = sizeZoomed; if (surface) { deviceHeight = (sizeZoomed * surface->LogPixelsY()) / 72; @@ -1589,7 +1589,7 @@ void ScintillaWin::HorizontalScrollMessage(WPARAM wParam) { void ScintillaWin::RealizeWindowPalette(bool inBackGround) { RefreshStyleData(); HDC hdc = ::GetDC(MainHWND()); - AutoSurface surfaceWindow(hdc, CodePage()); + AutoSurface surfaceWindow(hdc, this); if (surfaceWindow) { int changes = surfaceWindow->SetPalette(&palette, inBackGround); if (changes > 0) @@ -1608,7 +1608,7 @@ void ScintillaWin::FullPaint() { rcPaint = GetClientRectangle(); paintingAllText = true; HDC hdc = ::GetDC(MainHWND()); - AutoSurface surfaceWindow(hdc, CodePage()); + AutoSurface surfaceWindow(hdc, this); if (surfaceWindow) { Paint(surfaceWindow, rcPaint); surfaceWindow->Release(); @@ -1931,10 +1931,14 @@ sptr_t PASCAL ScintillaWin::CTWndProc( } else if (iMessage == WM_PAINT) { PAINTSTRUCT ps; ::BeginPaint(hWnd, &ps); - AutoSurface surfaceWindow(ps.hdc, ctp->codePage); + Surface *surfaceWindow = Surface::Allocate(); if (surfaceWindow) { + surfaceWindow->Init(ps.hdc, hWnd); + surfaceWindow->SetUnicodeMode(SC_CP_UTF8 == ctp->codePage); + surfaceWindow->SetDBCSMode(ctp->codePage); ctp->PaintCT(surfaceWindow); surfaceWindow->Release(); + delete surfaceWindow; } ::EndPaint(hWnd, &ps); return 0; |