diff options
| -rw-r--r-- | win32/PlatWin.cxx | 135 | 
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);  		} | 
