# HG changeset patch
# User Patrik Svestka <patrik.svestka@gmail.com>
# Date 1491301233 -7200
# Tue Apr 04 12:20:33 2017 +0200
# Branch jv
# Node ID edc9b78c5b42767cecfbf199b4f153c213237004
# Parent 76834c6940c7f04c6aa22cdd3669b263e64b0fb6
Issue #126: String text becomes invisible when string length exceeds buffer (an undocumented internal limit)
Short description: The patch fixes an issue, where strings longer are than 3275 characters, for both TextOutA and TextOutW (an undocumented internal limit).
Now such strings are correctly displayed.
Detailed description: The position of pX and pY is set by SetTextAlign(hDC, TA_UPDATECP) and MoveToEx(hDC, pX, pY, NULL). The side effect when
using TA_UPDATECP (sets the current point to the reference point) is that any TextOut will ignore pX and pY. Both TextOutA and TextOutW will
have pX=0 and pX=0. The MIN function is used for selecting the lowest value to display - never exceeding MAX_DISPLAY_BUFFER. The loop iterates
till it has nothing more toDisplay.
note: I have also added parentheses around MIN definition to avoid operator precedence problem in the future.
To see more about the issue visit:
https://swing.fit.cvut.cz/projects/stx-jv/ticket/126
diff -r 76834c6940c7 -r edc9b78c5b42 WinWorkstation.st
a
|
b
|
|
2800 | 2800 | lpmmi->ptMaxPosition.y = 0; |
2801 | 2801 | lpmmi->ptMaxSize.x = lI->currentMonitorWidth; |
2802 | 2802 | lpmmi->ptMaxSize.y = lI->currentMonitorHeight; |
2803 | | #define MIN(a, b) (a < b ? a : b) |
| 2803 | /* Added Extra parentheses to avoid operator precedence problem */ |
| 2804 | #define MIN(a,b) (((a)<(b))?(a):(b)) |
2804 | 2805 | lpmmi->ptMaxSize.x = MIN(GetSystemMetrics(SM_CXMAXIMIZED), lI->maxWidth); |
2805 | 2806 | lpmmi->ptMaxSize.y = MIN(GetSystemMetrics(SM_CYMAXIMIZED), lI->maxHeight); |
2806 | 2807 | |
… |
… |
|
10760 | 10761 | "draw a sub-string - if opaque is false, draw foreground only; otherwise, draw both |
10761 | 10762 | foreground and background characters. |
10762 | 10763 | If the coordinates are not integers, an error is triggered." |
10763 | | |
10764 | | %{ /* NOCONTEXT */ |
| 10764 | %{ /* NOCONTEXT */ |
| 10765 | /* NOTICE: |
| 10766 | * A change here was forced by (an undocumented) limited internal display buffer. |
| 10767 | * A check is needed to draw against such internal limit; then draw it chunk-by-chunk. |
| 10768 | */ |
| 10769 | |
10765 | 10770 | unsigned char *cp; |
10766 | 10771 | OBJ cls; |
10767 | | int i1, i2, l, n; |
| 10772 | int i1, i2, n, l, toDisplay; |
10768 | 10773 | int nInstBytes; |
10769 | 10774 | |
| 10775 | |
10770 | 10776 | if (__isExternalAddress(aGCId) |
10771 | 10777 | && __isNonNilObject(aString) |
10772 | 10778 | && __bothSmallInteger(index1, index2) |
… |
… |
|
10777 | 10783 | HDC hDC; |
10778 | 10784 | HFONT hOldFont; |
10779 | 10785 | |
| 10786 | /* Windows (as in 7 or newer) limits the string size for TextOut* to 3275 */ |
| 10787 | const int MAX_DISPLAY_BUFFER = 3275; |
| 10788 | |
10780 | 10789 | i1 = __intVal(index1) - 1; |
10781 | 10790 | i2 = __intVal(index2) - 1; |
10782 | 10791 | if ((i1 < 0) || (i2 < i1)) { |
… |
… |
|
10813 | 10822 | #endif |
10814 | 10823 | |
10815 | 10824 | cls = __qClass(aString); |
10816 | | |
10817 | 10825 | cp = __stringVal(aString); |
10818 | 10826 | l = i2 - i1 + 1; |
10819 | | if (l > 32758) { |
10820 | | /* Windows (as in XP) limits the string size for TextOut* to 32758 */ |
10821 | | l = 32758; |
10822 | | } |
| 10827 | toDisplay = l; |
| 10828 | |
| 10829 | /* Set the current point to the reference point. */ |
| 10830 | SetTextAlign(hDC, TA_UPDATECP); |
| 10831 | MoveToEx(hDC, pX, pY, NULL); |
10823 | 10832 | |
10824 | 10833 | if (__isStringLike(aString)) { |
10825 | 10834 | n = __stringSize(aString); |
10826 | 10835 | commonOutChars: |
10827 | 10836 | if (i2 < n) { |
10828 | | cp += i1; |
10829 | | CPRINTF(("string1: %s pos=%d/%d l=%d hDC=%x\n", cp, pX, pY,l,hDC)); |
10830 | | if (! TextOutA(hDC, pX, pY, (char *)cp, l)) { |
10831 | | PRINTF(("WinWorkstation [warning]: TextOutA failed. [%d]\n", __LINE__)); |
10832 | | PRINTF(("WinWorkstation [warning]: lastError=%d x:%d y:%d len:%d\n", GetLastError(), pX, pY, l)); |
10833 | | goto error; |
10834 | | } |
| 10837 | cp += i1; |
| 10838 | do { |
| 10839 | /* TA_UPDATECP used => pX, pY ignored */ |
| 10840 | if (! TextOutA(hDC, 0, 0, (char *)cp, MIN(toDisplay, MAX_DISPLAY_BUFFER))) { |
| 10841 | PRINTF(("WinWorkstation [warning]: TextOutA failed. [%d]\n", __LINE__)); |
| 10842 | PRINTF(("WinWorkstation [warning]: lastError=%d x:%d y:%d len:%d leftToShow=%d\n", GetLastError(), pX, pY, l, toDisplay)); |
| 10843 | goto error; |
| 10844 | } |
| 10845 | cp += MAX_DISPLAY_BUFFER; |
| 10846 | toDisplay -= MAX_DISPLAY_BUFFER; |
| 10847 | } while(toDisplay > 0); |
10835 | 10848 | } |
10836 | 10849 | goto ret; |
10837 | 10850 | } |
… |
… |
|
10847 | 10860 | /* Unicode */ |
10848 | 10861 | if (__isWords(aString)) { |
10849 | 10862 | n = n / 2; |
10850 | | if (i2 < n) { |
10851 | | WIDECHAR *w_cp = (WIDECHAR *)cp; |
10852 | | w_cp += i1; |
10853 | | if (! TextOutW(hDC, pX, pY, w_cp, l)) { |
10854 | | PRINTF(("WinWorkstation [warning]: TextOutW failed. [%d]\n", __LINE__)); |
10855 | | PRINTF(("WinWorkstation [warning]: lastError=%d x:%d y:%d len:%d\n", GetLastError(), pX, pY, l)); |
10856 | | } |
10857 | | goto ret; |
10858 | | } |
| 10863 | WIDECHAR *w_cp = (WIDECHAR *)cp; |
| 10864 | if (i2 < n){ |
| 10865 | w_cp += i1; |
| 10866 | do { |
| 10867 | /* TA_UPDATECP used => pX, pY ignored */ |
| 10868 | if (! TextOutW(hDC, 0, 0, w_cp, MIN(toDisplay, MAX_DISPLAY_BUFFER))) { |
| 10869 | PRINTF(("WinWorkstation [warning]: TextOutW failed. [%d]\n", __LINE__)); |
| 10870 | PRINTF(("WinWorkstation [warning]: lastError=%d x:%d y:%d len:%d leftToShow=%d\n", GetLastError(), pX, pY, l, toDisplay)); |
| 10871 | goto error; |
| 10872 | } |
| 10873 | w_cp += MAX_DISPLAY_BUFFER; |
| 10874 | toDisplay -= MAX_DISPLAY_BUFFER; |
| 10875 | } while (toDisplay > 0); |
| 10876 | } |
| 10877 | goto ret; |
10859 | 10878 | } |
10860 | 10879 | ret:; |
10861 | 10880 | #if 0 |