From 4f461745849c0906e742c3b6afa8a36aeb4493b3 Mon Sep 17 00:00:00 2001 From: nyamatongwe Date: Sat, 6 Sep 2008 10:43:51 +0000 Subject: Changes to improve handling of long lines. --- win32/PlatWin.cxx | 135 +++++++++++++++++++++++++++++++++--------------------- 1 file 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(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 +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 TextWide; +typedef VarBuffer 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(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 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 0) { + for (int i=0;ihDC, 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); } -- cgit v1.2.3