text.c 7.68 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
Alexandre Julliard's avatar
Alexandre Julliard committed
2
 *	PostScript driver text functions
Alexandre Julliard's avatar
Alexandre Julliard committed
3 4 5
 *
 *	Copyright 1998  Huw D M Davies
 *
6 7 8 9 10 11 12 13 14 15 16 17
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19 20
 */
#include <string.h>
21
#include <stdarg.h>
22
#include <stdlib.h>
23 24 25 26
#include <math.h>

#include "windef.h"
#include "wingdi.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
27
#include "psdrv.h"
28
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
29

30
WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
31

32 33 34 35 36 37 38
typedef struct tagRun {
    INT start;
    BOOL vertical;
    INT x;
    INT y;
}Run;

39
static BOOL PSDRV_Text(PHYSDEV dev, INT x, INT y, UINT flags,
40
		       LPCWSTR str, UINT count,
41
		       BOOL bDrawBackground, const INT *lpDx);
42

43
extern const unsigned short vertical_orientation_table[] DECLSPEC_HIDDEN;
44 45 46

static BOOL check_unicode_tategaki(WCHAR uchar)
{
47
    unsigned short orientation = vertical_orientation_table[vertical_orientation_table[vertical_orientation_table[uchar >> 8]+((uchar >> 4) & 0x0f)]+ (uchar & 0xf)];
48

49 50 51 52 53 54 55 56
    /* Type: U or Type: Tu */
    /* TODO Type: Tr,  Normally the logic for Tr would be that if
       Typographical substitution occurs, then do not rotate. However
       we have no facility at present to determine if GetGlyphIndices is
       successfully performing substitutions (well formed font) or not.
       Thus we are erroring on the side of the font being well formed,
       doing typographical substitution,  and so we are not doing rotation */
    return (orientation ==  1 || orientation == 2 || orientation == 3);
57 58 59 60
}

static Run* build_vertical_runs(PHYSDEV dev, UINT flags, LPCWSTR str, UINT count, INT *run_count)
{
61
    BOOL last_vert;
62 63 64 65 66 67
    INT start, end;
    INT array_size = 5;
    Run *run = HeapAlloc(GetProcessHeap(),0,sizeof(Run)*array_size);
    int index = 0;
    LOGFONTW lf;

68
    if (count && str && (!(flags & ETO_GLYPH_INDEX)) && GetObjectW( GetCurrentObject(dev->hdc, OBJ_FONT), sizeof(lf), &lf ) && (lf.lfFaceName[0] == '@'))
69
    {
70
        last_vert = check_unicode_tategaki(str[0]);
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
        start = end = 0;
        while (start < count)
        {
            int offset = 0;

            while (end < count && check_unicode_tategaki(str[end]) == last_vert)
                end++;

            run[index].start = start;
            run[index].vertical = last_vert;
            run[index].x = 0;
            run[index].y = 0;

            if (run[index].vertical)
            {
                TEXTMETRICW tm;
                GetTextMetricsW(dev->hdc, &tm);
                offset += PSDRV_XWStoDS(dev, tm.tmAscent - tm.tmInternalLeading);
            }

            if (start > 0)
            {
                SIZE size;
                GetTextExtentPointW(dev->hdc, str, start, &size);
                offset += PSDRV_XWStoDS(dev, size.cx);
            }

            if (offset)
            {
                double angle;
                angle = (lf.lfEscapement / 10.0) * M_PI / 180.0;
                run[index].y = -offset * sin(angle);
                run[index].x = -offset * cos(angle);
            }

            index ++;
            if (index >= array_size)
            {
                array_size *=2;
                run = HeapReAlloc(GetProcessHeap(), 0, run, sizeof(Run)*array_size);
            }
            start = end;
            if (start < count)
                last_vert = check_unicode_tategaki(str[end]);
        }
    }
    else
    {
        run[0].start = 0;
        run[0].vertical = 0;
        run[0].x = 0;
        run[0].y = 0;
        index = 1;
    }
    *run_count = index;
    return run;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
129 130 131
/***********************************************************************
 *           PSDRV_ExtTextOut
 */
132 133
BOOL PSDRV_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags, const RECT *lprect, LPCWSTR str, UINT count,
                       const INT *lpDx )
Alexandre Julliard's avatar
Alexandre Julliard committed
134
{
135
    PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
136
    BOOL bResult = TRUE;
137 138
    BOOL bClipped = FALSE;
    BOOL bOpaque = FALSE;
139 140 141
    Run *runs = NULL;
    int run_count = 0;
    int i = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
142

143 144
    TRACE("(x=%d, y=%d, flags=0x%08x, str=%s, count=%d, lpDx=%p)\n", x, y,
	  flags, debugstr_wn(str, count), count, lpDx);
Alexandre Julliard's avatar
Alexandre Julliard committed
145

146
    if(physDev->job.id == 0) return FALSE;
147

148
    runs = build_vertical_runs(dev, flags, str, count, &run_count);
149

150 151
    /* set draw background */
    if ((flags & ETO_OPAQUE) && (lprect != NULL))
152
    {
153 154 155 156 157 158 159 160 161 162 163
        PSDRV_SetClip(dev);
        PSDRV_WriteGSave(dev);
        PSDRV_WriteRectangle(dev, lprect->left, lprect->top, lprect->right - lprect->left,
                     lprect->bottom - lprect->top);

        bOpaque = TRUE;
        PSDRV_WriteSetColor(dev, &physDev->bkColor);
        PSDRV_WriteFill(dev);

        PSDRV_WriteGRestore(dev);
        PSDRV_ResetClip(dev);
164
    }
165 166

    while (i < run_count)
167
    {
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
        int cnt;

        if (i != run_count - 1)
            cnt = runs[i+1].start- runs[i].start;
        else
            cnt = count - runs[i].start;

        PSDRV_SetFont(dev, runs[i].vertical);

        PSDRV_SetClip(dev);

        /* set clipping */
        if ((flags & ETO_CLIPPED) && (lprect != NULL))
        {
            PSDRV_WriteGSave(dev);

            PSDRV_WriteRectangle(dev, lprect->left, lprect->top, lprect->right - lprect->left,
                     lprect->bottom - lprect->top);

            bClipped = TRUE;
            PSDRV_WriteClip(dev);

            bResult = PSDRV_Text(dev, runs[i].x+x, runs[i].y+y, flags, &str[runs[i].start], cnt, !(bClipped && bOpaque), (lpDx)?&lpDx[runs[i].start]:NULL);

            PSDRV_WriteGRestore(dev);
        }
        else
            bResult = PSDRV_Text(dev, runs[i].x+x, runs[i].y+y, flags, &str[runs[i].start], cnt, TRUE, (lpDx)?&lpDx[runs[i].start]:NULL);

        i++;
        PSDRV_ResetClip(dev);
199 200
    }

201
    HeapFree(GetProcessHeap(),0,runs);
202 203 204 205 206 207
    return bResult;
}

/***********************************************************************
 *           PSDRV_Text
 */
208
static BOOL PSDRV_Text(PHYSDEV dev, INT x, INT y, UINT flags, LPCWSTR str,
209
		       UINT count, BOOL bDrawBackground, const INT *lpDx)
210
{
211
    PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
212
    WORD *glyphs = NULL;
213

214 215 216
    if (!count)
	return TRUE;

217 218 219 220 221 222
    if(physDev->font.fontloc == Download && !(flags & ETO_GLYPH_INDEX))
    {
        glyphs = HeapAlloc( GetProcessHeap(), 0, count * sizeof(WORD) );
        GetGlyphIndicesW( dev->hdc, str, count, glyphs, 0 );
        str = glyphs;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
223

224
    PSDRV_WriteMoveTo(dev, x, y);
225

226
    if(!lpDx) {
227
        if(physDev->font.fontloc == Download)
228
	    PSDRV_WriteDownloadGlyphShow(dev, str, count);
229
	else
230
	    PSDRV_WriteBuiltinGlyphShow(dev, str, count);
231
    }
232
    else {
233
        UINT i;
234 235
	POINT offset = {0, 0};

236
        for(i = 0; i < count-1; i++) {
237
	    if(physDev->font.fontloc == Download)
238
	        PSDRV_WriteDownloadGlyphShow(dev, str + i, 1);
239
	    else
240
	        PSDRV_WriteBuiltinGlyphShow(dev, str + i, 1);
241 242 243 244 245 246 247
            if(flags & ETO_PDY)
            {
                offset.x += lpDx[i * 2];
                offset.y += lpDx[i * 2 + 1];
            }
            else
                offset.x += lpDx[i];
248
	    PSDRV_WriteMoveTo(dev, x + offset.x, y + offset.y);
249
	}
250
	if(physDev->font.fontloc == Download)
251
	    PSDRV_WriteDownloadGlyphShow(dev, str + i, 1);
252
	else
253
	    PSDRV_WriteBuiltinGlyphShow(dev, str + i, 1);
254 255
    }

256
    HeapFree( GetProcessHeap(), 0, glyphs );
Alexandre Julliard's avatar
Alexandre Julliard committed
257 258
    return TRUE;
}