📄 platgtk.cxx.svn-base
字号:
}
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;
len = strlen(utfForm);
return utfForm;
}
static size_t UTF8CharLength(const char *s) {
const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
unsigned char ch = *us;
if (ch < 0x80) {
return 1;
} else if (ch < 0x80 + 0x40 + 0x20) {
return 2;
} else {
return 3;
}
}
#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) {
int x = rc.left;
#ifdef USE_PANGO
if (PFont(font_)->pfd) {
char *utfForm = 0;
bool useGFree = false;
if (et == UTF8) {
pango_layout_set_text(layout, s, len);
} else {
if (!utfForm) {
SetConverter(PFont(font_)->characterSet);
utfForm = UTF8FromIconv(conv, s, len);
}
if (!utfForm) { // iconv failed so try DBCS if DBCS mode
if (et == dbcs) {
// Convert to utf8
utfForm = UTF8FromDBCS(s, len);
}
}
if (!utfForm) { // iconv and DBCS failed so treat as Latin1
utfForm = UTF8FromLatin1(s, len);
}
pango_layout_set_text(layout, utfForm, len);
}
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);
if (useGFree) {
g_free(utfForm);
} else {
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 (et != singleByte) {
GdkWChar wctext[maxLengthTextRun];
if (len >= maxLengthTextRun)
len = maxLengthTextRun-1;
int wclen;
if (et == UTF8) {
wclen = UCS2FromUTF8(s, len,
static_cast<wchar_t *>(static_cast<void *>(wctext)), maxLengthTextRun - 1);
} else { // dbcs, so convert using current locale
char sMeasure[maxLengthTextRun];
memcpy(sMeasure, s, len);
sMeasure[len] = '\0';
wclen = gdk_mbstowcs(
wctext, sMeasure, maxLengthTextRun - 1);
}
if (wclen > 0) {
draw8bit = false;
wctext[wclen] = L'\0';
GdkWChar *wcp = wctext;
while ((wclen > 0) && (x < maxCoordinate)) {
int lenDraw = Platform::Minimum(wclen, segmentLength);
gdk_draw_text_wc(drawable, PFont(font_)->pfont, gc,
x, ybase, wcp, lenDraw);
wclen -= lenDraw;
if (wclen > 0) { // Avoid next calculation if possible as may be expensive
x += gdk_text_width_wc(PFont(font_)->pfont,
wcp, lenDraw);
}
wcp += lenDraw;
}
}
}
if (draw8bit) {
while ((len > 0) && (x < maxCoordinate)) {
int lenDraw = Platform::Minimum(len, segmentLength);
gdk_draw_text(drawable, PFont(font_)->pfont, gc,
x, ybase, s, lenDraw);
len -= lenDraw;
if (len > 0) { // Avoid next calculation if possible as may be expensive
x += gdk_text_width(PFont(font_)->pfont, s, lenDraw);
}
s += lenDraw;
}
}
}
}
void SurfaceImpl::DrawTextNoClip(PRectangle rc, Font &font_, int ybase, const char *s, int len,
ColourAllocated fore, ColourAllocated back) {
FillRectangle(rc, back);
DrawTextBase(rc, font_, ybase, s, len, fore);
}
// On GTK+, exactly same as DrawTextNoClip
void SurfaceImpl::DrawTextClipped(PRectangle rc, Font &font_, int ybase, const char *s, int len,
ColourAllocated fore, ColourAllocated back) {
FillRectangle(rc, back);
DrawTextBase(rc, font_, ybase, s, len, fore);
}
void SurfaceImpl::DrawTextTransparent(PRectangle rc, Font &font_, int ybase, const char *s, int len,
ColourAllocated fore) {
// Avoid drawing spaces in transparent mode
for (int i=0;i<len;i++) {
if (s[i] != ' ') {
DrawTextBase(rc, font_, ybase, s, len, fore);
return;
}
}
}
void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positions) {
if (font_.GetID()) {
int totalWidth = 0;
#ifdef USE_PANGO
const int lenPositions = len;
if (PFont(font_)->pfd) {
if (len == 1) {
int width = PFont(font_)->CharWidth(*s, et);
if (width) {
positions[0] = width;
return;
}
}
PangoRectangle pos;
pango_layout_set_font_description(layout, PFont(font_)->pfd);
if (et == UTF8) {
// Simple and direct as UTF-8 is native Pango encoding
pango_layout_set_text(layout, s, len);
PangoLayoutIter *iter = pango_layout_get_iter(layout);
pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
int i = 0;
while (pango_layout_iter_next_cluster(iter)) {
pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
int position = PANGO_PIXELS(pos.x);
int curIndex = pango_layout_iter_get_index(iter);
while (i < curIndex) {
positions[i++] = position;
}
}
while (i < lenPositions)
positions[i++] = PANGO_PIXELS(pos.x + pos.width);
pango_layout_iter_free(iter);
PLATFORM_ASSERT(i == lenPositions);
} else {
int positionsCalculated = 0;
if (et == dbcs) {
SetConverter(PFont(font_)->characterSet);
char *utfForm = UTF8FromIconv(conv, s, len);
if (utfForm) {
// 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.
Converter convMeasure("UCS-2", CharacterSetID(characterSet), false);
pango_layout_set_text(layout, utfForm, strlen(utfForm));
int i = 0;
int utfIndex = 0;
PangoLayoutIter *iter = pango_layout_get_iter(layout);
pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
while (pango_layout_iter_next_cluster(iter)) {
pango_layout_iter_get_cluster_extents (iter, NULL, &pos);
int position = PANGO_PIXELS(pos.x);
int utfIndexNext = pango_layout_iter_get_index(iter);
while (utfIndex < utfIndexNext) {
size_t lenChar = MultiByteLenFromIconv(convMeasure, s+i, len-i);
//size_t lenChar = mblen(s+i, MB_CUR_MAX);
while (lenChar--) {
positions[i++] = position;
positionsCalculated++;
}
utfIndex += UTF8CharLength(utfForm+utfIndex);
}
}
while (i < lenPositions)
positions[i++] = PANGO_PIXELS(pos.x + pos.width);
pango_layout_iter_free(iter);
delete []utfForm;
PLATFORM_ASSERT(i == lenPositions);
}
}
if (positionsCalculated < 1 ) {
// Either Latin1 or DBCS conversion failed so treat as Latin1.
bool useGFree = false;
SetConverter(PFont(font_)->characterSet);
char *utfForm = UTF8FromIconv(conv, s, len);
if (!utfForm) {
utfForm = UTF8FromLatin1(s, len);
}
pango_layout_set_text(layout, utfForm, len);
int i = 0;
PangoLayoutIter *iter = pango_layout_get_iter(layout);
pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
while (pango_layout_iter_next_cluster(iter)) {
pango_layout_iter_get_cluster_extents(iter, NULL, &pos);
positions[i++] = PANGO_PIXELS(pos.x);
}
while (i < lenPositions)
positions[i++] = PANGO_PIXELS(pos.x + pos.width);
pango_layout_iter_free(iter);
if (useGFree) {
g_free(utfForm);
} else {
delete []utfForm;
}
PLATFORM_ASSERT(i == lenPositions);
}
}
if (len == 1) {
PFont(font_)->SetCharWidth(*s, positions[0], et);
}
return;
}
#endif
GdkFont *gf = PFont(font_)->pfont;
bool measure8bit = true;
if (et != singleByte) {
GdkWChar wctext[maxLengthTextRun];
if (len >= maxLengthTextRun)
len = maxLengthTextRun-1;
int wclen;
if (et == UTF8) {
wclen = UCS2FromUTF8(s, len,
static_cast<wchar_t *>(static_cast<void *>(wctext)), maxLengthTextRun - 1);
} else { // dbcsMode, so convert using current locale
char sDraw[maxLengthTextRun];
memcpy(sDraw, s, len);
sDraw[len] = '\0';
wclen = gdk_mbstowcs(
wctext, sDraw, maxLengthTextRun - 1);
}
if (wclen > 0) {
measure8bit = false;
wctext[wclen] = L'\0';
// 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;
int lenChar;
if (et == UTF8) {
lenChar = UTF8Len(s[i]);
} else {
lenChar = mblen(s+i, MB_CUR_MAX);
if (lenChar < 0)
lenChar = 1;
}
while (lenChar--) {
positions[i++] = totalWidth;
}
}
while (i < len) { // In case of problems with lengths
positions[i++] = totalWidth;
}
}
}
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;
positions[i] = totalWidth;
}
}
} else {
// No font so return an ascending range of values
for (int i = 0; i < len; i++) {
positions[i] = i + 1;
}
}
}
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;
bool useGFree = false;
if (et == UTF8) {
pango_layout_set_text(layout, s, len);
} else {
if (et == dbcs) {
// Convert to utf8
utfForm = UTF8FromDBCS(s, len);
}
if (!utfForm) { // DBCS failed so treat as iconv
SetConverter(PFont(font_)->characterSet);
utfForm = UTF8FromIconv(conv, s, len);
}
if (!utfForm) { // g_locale_to_utf8 failed so treat as Latin1
utfForm = UTF8FromLatin1(s, len);
}
pango_layout_set_text(layout, utfForm, len);
}
PangoLayoutLine *pangoLine = pango_layout_get_line(layout, 0);
pango_layout_line_get_extents(pangoLine, NULL, &pos);
if (useGFree) {
g_free(utfForm);
} else {
delete []utfForm;
}
return PANGO_PIXELS(pos.width);
}
#endif
if (et == UTF8) {
GdkWChar wctext[maxLengthTextRun];
size_t wclen = UCS2FromUTF8(s, len, static_cast<wchar_t *>(static_cast<void *>(wctext)),
sizeof(wctext) / sizeof(GdkWChar) - 1);
wctext[wclen] = L'\0';
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()) {
#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:
// 1) Call gdk_string_extents with string containing all letters, numbers and punctuation.
// 2) Use the ascent and descent fields of GdkFont.
// 3) Call gdk_string_extents with string as 1 but also including accented capitals.
// Smallest values given by 1 and largest by 3 with 2 in between.
// Techniques 1 and 2 sometimes chop off extreme portions of ascenders and
// descenders but are mostly OK except for accented characters like
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -