aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--win32/PlatWin.cxx135
1 files changed, 82 insertions, 53 deletions
diff --git a/win32/PlatWin.cxx b/win32/PlatWin.cxx
index 09d97917a..3f0ddd9fb 100644
--- a/win32/PlatWin.cxx
+++ b/win32/PlatWin.cxx
@@ -663,7 +663,32 @@ void SurfaceImpl::Copy(PRectangle rc, Point from, Surface &surfaceSource) {
static_cast<SurfaceImpl &>(surfaceSource).hdc, from.x, from.y, SRCCOPY);
}
-const int MAX_US_LEN = 10000;
+// Buffer to hold size strings and string position arrays without always allocating on heap.
+// May sometimes have string too long to allocate on stack. So use a fixed stack-allocated buffer
+// when less than safe size otherwise allocate on heap and free automatically.
+template<typename T, int lengthStandard>
+class VarBuffer {
+ T bufferStandard[lengthStandard];
+public:
+ T *buffer;
+ VarBuffer(size_t length) : buffer(0) {
+ if (length > lengthStandard) {
+ buffer = new T[length];
+ } else {
+ buffer = bufferStandard;
+ }
+ }
+ ~VarBuffer() {
+ if (buffer != bufferStandard) {
+ delete []buffer;
+ buffer = 0;
+ }
+ }
+};
+
+const int stackBufferLength = 10000;
+typedef VarBuffer<wchar_t, stackBufferLength> TextWide;
+typedef VarBuffer<int, stackBufferLength> TextPositions;
void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const char *s, int len, UINT fuOptions) {
SetFont(font_);
@@ -693,25 +718,22 @@ void SurfaceImpl::DrawTextCommon(PRectangle rc, Font &font_, int ybase, const ch
}
} else {
// Use Unicode calls
- wchar_t tbuf[MAX_US_LEN];
+ TextWide tbuf(len);
int tlen;
if (unicodeMode) {
- tlen = UTF16FromUTF8(s, len, tbuf, MAX_US_LEN);
+ tlen = UTF16FromUTF8(s, len, tbuf.buffer, len);
} else {
// Support Asian string display in 9x English
- tlen = ::MultiByteToWideChar(codePage, 0, s, len, NULL, 0);
- if (tlen > MAX_US_LEN)
- tlen = MAX_US_LEN;
- ::MultiByteToWideChar(codePage, 0, s, len, tbuf, tlen);
+ tlen = ::MultiByteToWideChar(codePage, 0, s, len, tbuf.buffer, len);
}
- if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf, tlen, NULL)) {
+ if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf.buffer, tlen, NULL)) {
while (tlen > pos) {
int seglen = Platform::Minimum(maxSegmentLength, tlen - pos);
- if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf+pos, seglen, NULL)) {
+ if (!::ExtTextOutW(hdc, x, ybase, fuOptions, &rcw, tbuf.buffer+pos, seglen, NULL)) {
PLATFORM_ASSERT(false);
return;
}
- ::GetTextExtentPoint32W(hdc, tbuf+pos, seglen, &sz);
+ ::GetTextExtentPoint32W(hdc, tbuf.buffer+pos, seglen, &sz);
x += sz.cx;
pos += seglen;
}
@@ -751,17 +773,16 @@ int SurfaceImpl::WidthText(Font &font_, const char *s, int len) {
SetFont(font_);
SIZE sz={0,0};
if (unicodeMode) {
- wchar_t tbuf[MAX_US_LEN];
- int tlen = UTF16FromUTF8(s, len, tbuf, MAX_US_LEN);
- ::GetTextExtentPoint32W(hdc, tbuf, tlen, &sz);
+ TextWide tbuf(len);
+ int tlen = UTF16FromUTF8(s, len, tbuf.buffer, len);
+ ::GetTextExtentPoint32W(hdc, tbuf.buffer, tlen, &sz);
} else if (IsNT() || (codePage==0) || win9xACPSame) {
::GetTextExtentPoint32A(hdc, s, Platform::Minimum(len, maxLenText), &sz);
} else {
// Support Asian string display in 9x English
- wchar_t tbuf[MAX_US_LEN];
- int tlen = ::MultiByteToWideChar(codePage, 0, s, len, NULL, 0);
- ::MultiByteToWideChar(codePage, 0, s, len, tbuf, tlen);
- ::GetTextExtentPoint32W(hdc, tbuf, tlen, &sz);
+ TextWide tbuf(len);
+ int tlen = ::MultiByteToWideChar(codePage, 0, s, len, tbuf.buffer, len);
+ ::GetTextExtentPoint32W(hdc, tbuf.buffer, tlen, &sz);
}
return sz.cx;
}
@@ -771,20 +792,20 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi
SIZE sz={0,0};
int fit = 0;
if (unicodeMode) {
- wchar_t tbuf[MAX_US_LEN];
- int tlen = UTF16FromUTF8(s, len, tbuf, MAX_US_LEN);
- int poses[MAX_US_LEN];
+ TextWide tbuf(len);
+ int tlen = UTF16FromUTF8(s, len, tbuf.buffer, len);
+ TextPositions poses(tlen);
fit = tlen;
- if (!::GetTextExtentExPointW(hdc, tbuf, tlen, maxWidthMeasure, &fit, poses, &sz)) {
+ if (!::GetTextExtentExPointW(hdc, tbuf.buffer, tlen, maxWidthMeasure, &fit, poses.buffer, &sz)) {
// Likely to have failed because on Windows 9x where function not available
// So measure the character widths by measuring each initial substring
// Turns a linear operation into a qudratic but seems fast enough on test files
for (int widthSS=0; widthSS < tlen; widthSS++) {
- ::GetTextExtentPoint32W(hdc, tbuf, widthSS+1, &sz);
- poses[widthSS] = sz.cx;
+ ::GetTextExtentPoint32W(hdc, tbuf.buffer, widthSS+1, &sz);
+ poses.buffer[widthSS] = sz.cx;
}
}
- // Map the widths given for UCS-2 characters back onto the UTF-8 input string
+ // Map the widths given for UTF-16 characters back onto the UTF-8 input string
int ui=0;
const unsigned char *us = reinterpret_cast<const unsigned char *>(s);
int i=0;
@@ -800,7 +821,7 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi
lenChar = 2;
}
for (unsigned int bytePos=0; (bytePos<lenChar) && (i<len); bytePos++) {
- positions[i++] = poses[ui];
+ positions[i++] = poses.buffer[ui];
}
ui++;
}
@@ -811,37 +832,47 @@ void SurfaceImpl::MeasureWidths(Font &font_, const char *s, int len, int *positi
positions[i++] = lastPos;
}
} else if (IsNT() || (codePage==0) || win9xACPSame) {
- if (!::GetTextExtentExPointA(hdc, s, Platform::Minimum(len, maxLenText),
- maxWidthMeasure, &fit, positions, &sz)) {
- // Eeek - a NULL DC or other foolishness could cause this.
- // The least we can do is set the positions to zero!
- memset(positions, 0, len * sizeof(*positions));
- } else if (fit < len) {
- // For some reason, such as an incomplete DBCS character
- // Not all the positions are filled in so make them equal to end.
- for (int i=fit;i<len;i++)
- positions[i] = positions[fit-1];
+ // Zero positions to avoid random behaviour on failure.
+ memset(positions, 0, len * sizeof(*positions));
+ // len may be larger than platform supports so loop over segments small enough for platform
+ int startOffset = 0;
+ while (len > 0) {
+ int lenBlock = Platform::Minimum(len, maxLenText);
+ if (!::GetTextExtentExPointA(hdc, s, lenBlock, maxWidthMeasure, &fit, positions, &sz)) {
+ // Eeek - a NULL DC or other foolishness could cause this.
+ return;
+ } else if (fit < lenBlock) {
+ // For some reason, such as an incomplete DBCS character
+ // Not all the positions are filled in so make them equal to end.
+ for (int i=fit;i<lenBlock;i++)
+ positions[i] = positions[fit-1];
+ } else if (startOffset > 0) {
+ for (int i=0;i<lenBlock;i++)
+ positions[i] += startOffset;
+ }
+ startOffset = positions[lenBlock-1];
+ len -= lenBlock;
+ positions += lenBlock;
+ s += lenBlock;
}
} else {
// Support Asian string display in 9x English
- wchar_t tbuf[MAX_US_LEN];
- int tlen = ::MultiByteToWideChar(codePage, 0, s, len, NULL, 0);
- ::MultiByteToWideChar(codePage, 0, s, len, tbuf, tlen);
-
- int poses[MAX_US_LEN];
+ TextWide tbuf(len);
+ int tlen = ::MultiByteToWideChar(codePage, 0, s, len, tbuf.buffer, len);
+ TextPositions poses(tlen);
for (int widthSS=0; widthSS<tlen; widthSS++) {
- ::GetTextExtentPoint32W(hdc, tbuf, widthSS+1, &sz);
- poses[widthSS] = sz.cx;
+ ::GetTextExtentPoint32W(hdc, tbuf.buffer, widthSS+1, &sz);
+ poses.buffer[widthSS] = sz.cx;
}
int ui = 0;
for (int i=0;i<len;) {
if (::IsDBCSLeadByteEx(codePage, s[i])) {
- positions[i] = poses[ui];
- positions[i+1] = poses[ui];
+ positions[i] = poses.buffer[ui];
+ positions[i+1] = poses.buffer[ui];
i += 2;
} else {
- positions[i] = poses[ui];
+ positions[i] = poses.buffer[ui];
i++;
}
@@ -1354,10 +1385,9 @@ PRectangle ListBoxX::GetDesiredRect() {
SIZE textSize = {0, 0};
int len = widestItem ? strlen(widestItem) : 0;
if (unicodeMode) {
- wchar_t tbuf[MAX_US_LEN];
- len = UTF16FromUTF8(widestItem, len, tbuf, sizeof(tbuf)/sizeof(wchar_t)-1);
- tbuf[len] = L'\0';
- ::GetTextExtentPoint32W(hdc, tbuf, len, &textSize);
+ TextWide tbuf(len);
+ len = UTF16FromUTF8(widestItem, len, tbuf.buffer, len);
+ ::GetTextExtentPoint32W(hdc, tbuf.buffer, len, &textSize);
} else {
::GetTextExtentPoint32A(hdc, widestItem, len, &textSize);
}
@@ -1473,10 +1503,9 @@ void ListBoxX::Draw(DRAWITEMSTRUCT *pDrawItem) {
::InsetRect(&rcText, TextInset.x, TextInset.y);
if (unicodeMode) {
- wchar_t tbuf[MAX_US_LEN];
- int tlen = UTF16FromUTF8(text, len, tbuf, sizeof(tbuf)/sizeof(wchar_t)-1);
- tbuf[tlen] = L'\0';
- ::DrawTextW(pDrawItem->hDC, tbuf, tlen, &rcText, DT_NOPREFIX|DT_END_ELLIPSIS|DT_SINGLELINE|DT_NOCLIP);
+ TextWide tbuf(len);
+ int tlen = UTF16FromUTF8(text, len, tbuf.buffer, len);
+ ::DrawTextW(pDrawItem->hDC, tbuf.buffer, tlen, &rcText, DT_NOPREFIX|DT_END_ELLIPSIS|DT_SINGLELINE|DT_NOCLIP);
} else {
::DrawTextA(pDrawItem->hDC, text, len, &rcText, DT_NOPREFIX|DT_END_ELLIPSIS|DT_SINGLELINE|DT_NOCLIP);
}