/* * PostScript driver text functions * * Copyright 1998 Huw D M Davies * * 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 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "psdrv.h" #include "winspool.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(psdrv); static BOOL PSDRV_Text(PSDRV_PDEVICE *physDev, INT x, INT y, UINT flags, LPCWSTR str, UINT count, BOOL bDrawBackground, const INT *lpDx); /*********************************************************************** * PSDRV_ExtTextOut */ BOOL PSDRV_ExtTextOut( PSDRV_PDEVICE *physDev, INT x, INT y, UINT flags, const RECT *lprect, LPCWSTR str, UINT count, const INT *lpDx, INT breakExtra ) { BOOL bResult = TRUE; BOOL bClipped = FALSE; BOOL bOpaque = FALSE; RECT rect; TRACE("(x=%d, y=%d, flags=0x%08x, str=%s, count=%d, lpDx=%p)\n", x, y, flags, debugstr_wn(str, count), count, lpDx); /* write font if not already written */ PSDRV_SetFont(physDev); PSDRV_SetClip(physDev); /* set clipping and/or draw background */ if ((flags & (ETO_CLIPPED | ETO_OPAQUE)) && (lprect != NULL)) { rect = *lprect; LPtoDP( physDev->hdc, (POINT *)&rect, 2 ); PSDRV_WriteGSave(physDev); PSDRV_WriteRectangle(physDev, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); if (flags & ETO_OPAQUE) { bOpaque = TRUE; PSDRV_WriteGSave(physDev); PSDRV_WriteSetColor(physDev, &physDev->bkColor); PSDRV_WriteFill(physDev); PSDRV_WriteGRestore(physDev); } if (flags & ETO_CLIPPED) { bClipped = TRUE; PSDRV_WriteClip(physDev); } bResult = PSDRV_Text(physDev, x, y, flags, str, count, !(bClipped && bOpaque), lpDx); PSDRV_WriteGRestore(physDev); } else { bResult = PSDRV_Text(physDev, x, y, flags, str, count, TRUE, lpDx); } PSDRV_ResetClip(physDev); return bResult; } /*********************************************************************** * PSDRV_Text */ static BOOL PSDRV_Text(PSDRV_PDEVICE *physDev, INT x, INT y, UINT flags, LPCWSTR str, UINT count, BOOL bDrawBackground, const INT *lpDx) { SIZE sz; TEXTMETRICW tm; POINT pt; INT ascent, descent; WORD *glyphs = NULL; UINT align = GetTextAlign( physDev->hdc ); INT char_extra; INT *deltas = NULL; double cosEsc, sinEsc; LOGFONTW lf; if (!count) return TRUE; GetObjectW(GetCurrentObject(physDev->hdc, OBJ_FONT), sizeof(lf), &lf); if(lf.lfEscapement != 0) { cosEsc = cos(lf.lfEscapement * M_PI / 1800); sinEsc = sin(lf.lfEscapement * M_PI / 1800); } else { cosEsc = 1; sinEsc = 0; } if(physDev->font.fontloc == Download) { if(flags & ETO_GLYPH_INDEX) glyphs = (LPWORD)str; else { glyphs = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WORD)); GetGlyphIndicesW(physDev->hdc, str, count, glyphs, 0); } } pt.x = x; pt.y = y; if(align & TA_UPDATECP) GetCurrentPositionEx( physDev->hdc, &pt ); LPtoDP(physDev->hdc, &pt, 1); x = pt.x; y = pt.y; if(physDev->font.fontloc == Download) GetTextExtentPointI(physDev->hdc, glyphs, count, &sz); else GetTextExtentPoint32W(physDev->hdc, str, count, &sz); if((char_extra = GetTextCharacterExtra(physDev->hdc)) != 0) { UINT i; SIZE tmpsz; deltas = HeapAlloc(GetProcessHeap(), 0, count * sizeof(INT)); for(i = 0; i < count; i++) { if(lpDx) deltas[i] = lpDx[i] + char_extra; else { if(physDev->font.fontloc == Download) GetTextExtentPointI(physDev->hdc, glyphs + i, 1, &tmpsz); else GetTextExtentPoint32W(physDev->hdc, str + i, 1, &tmpsz); deltas[i] = tmpsz.cx; } } } else if(lpDx) deltas = (INT*)lpDx; if(deltas) { SIZE tmpsz; UINT i; /* Get the width of the last char and add on all the offsets */ if(physDev->font.fontloc == Download) GetTextExtentPointI(physDev->hdc, glyphs + count - 1, 1, &tmpsz); else GetTextExtentPoint32W(physDev->hdc, str + count - 1, 1, &tmpsz); for(i = 0; i < count-1; i++) tmpsz.cx += deltas[i]; sz.cx = tmpsz.cx; /* sz.cy remains untouched */ } sz.cx = PSDRV_XWStoDS(physDev, sz.cx); sz.cy = PSDRV_YWStoDS(physDev, sz.cy); GetTextMetricsW(physDev->hdc, &tm); ascent = abs(PSDRV_YWStoDS(physDev, tm.tmAscent)); descent = abs(PSDRV_YWStoDS(physDev, tm.tmDescent)); TRACE("textAlign = %x\n", align); switch(align & (TA_LEFT | TA_CENTER | TA_RIGHT) ) { case TA_LEFT: if(align & TA_UPDATECP) { POINT pt; pt.x = x + sz.cx * cosEsc; pt.y = y - sz.cx * sinEsc; DPtoLP( physDev->hdc, &pt, 1 ); MoveToEx( physDev->hdc, pt.x, pt.y, NULL ); } break; case TA_CENTER: x -= sz.cx * cosEsc / 2; y += sz.cx * sinEsc / 2; break; case TA_RIGHT: x -= sz.cx * cosEsc; y += sz.cx * sinEsc; if(align & TA_UPDATECP) { POINT pt; pt.x = x; pt.y = y; DPtoLP( physDev->hdc, &pt, 1 ); MoveToEx( physDev->hdc, pt.x, pt.y, NULL ); } break; } switch(align & (TA_TOP | TA_BASELINE | TA_BOTTOM) ) { case TA_TOP: y += ascent * cosEsc; x += ascent * sinEsc; break; case TA_BASELINE: break; case TA_BOTTOM: y -= descent * cosEsc; x -= descent * sinEsc; break; } if ((GetBkMode( physDev->hdc ) != TRANSPARENT) && bDrawBackground) { PSDRV_WriteGSave(physDev); PSDRV_WriteNewPath(physDev); PSDRV_WriteRectangle(physDev, x, y - ascent, sz.cx, ascent + descent); PSDRV_WriteSetColor(physDev, &physDev->bkColor); PSDRV_WriteFill(physDev); PSDRV_WriteGRestore(physDev); } PSDRV_WriteMoveTo(physDev, x, y); if(!deltas) { if(physDev->font.fontloc == Download) PSDRV_WriteDownloadGlyphShow(physDev, glyphs, count); else PSDRV_WriteBuiltinGlyphShow(physDev, str, count); } else { UINT i; float dx = 0.0, dy = 0.0; float cos_theta = cos(physDev->font.escapement * M_PI / 1800.0); float sin_theta = sin(physDev->font.escapement * M_PI / 1800.0); for(i = 0; i < count-1; i++) { TRACE("lpDx[%d] = %d\n", i, deltas[i]); if(physDev->font.fontloc == Download) PSDRV_WriteDownloadGlyphShow(physDev, glyphs + i, 1); else PSDRV_WriteBuiltinGlyphShow(physDev, str + i, 1); dx += deltas[i] * cos_theta; dy -= deltas[i] * sin_theta; PSDRV_WriteMoveTo(physDev, x + PSDRV_XWStoDS(physDev, dx), y + PSDRV_YWStoDS(physDev, dy)); } if(physDev->font.fontloc == Download) PSDRV_WriteDownloadGlyphShow(physDev, glyphs + i, 1); else PSDRV_WriteBuiltinGlyphShow(physDev, str + i, 1); if(deltas != lpDx) HeapFree(GetProcessHeap(), 0, deltas); } /* * Underline and strikeout attributes. */ if ((tm.tmUnderlined) || (tm.tmStruckOut)) { /* Get the thickness and the position for the underline attribute */ /* We'll use the same thickness for the strikeout attribute */ INT escapement = physDev->font.escapement; /* Do the underline */ if (tm.tmUnderlined) { PSDRV_WriteNewPath(physDev); /* will be closed by WriteRectangle */ if (escapement != 0) /* rotated text */ { PSDRV_WriteGSave(physDev); /* save the graphics state */ PSDRV_WriteMoveTo(physDev, x, y); /* move to the start */ /* temporarily rotate the coord system */ PSDRV_WriteRotate(physDev, -escapement/10); /* draw the underline relative to the starting point */ PSDRV_WriteRRectangle(physDev, 0, -physDev->font.underlinePosition, sz.cx, physDev->font.underlineThickness); } else PSDRV_WriteRectangle(physDev, x, y - physDev->font.underlinePosition, sz.cx, physDev->font.underlineThickness); PSDRV_WriteFill(physDev); if (escapement != 0) /* rotated text */ PSDRV_WriteGRestore(physDev); /* restore the graphics state */ } /* Do the strikeout */ if (tm.tmStruckOut) { PSDRV_WriteNewPath(physDev); /* will be closed by WriteRectangle */ if (escapement != 0) /* rotated text */ { PSDRV_WriteGSave(physDev); /* save the graphics state */ PSDRV_WriteMoveTo(physDev, x, y); /* move to the start */ /* temporarily rotate the coord system */ PSDRV_WriteRotate(physDev, -escapement/10); /* draw the line relative to the starting point */ PSDRV_WriteRRectangle(physDev, 0, -physDev->font.strikeoutPosition, sz.cx, physDev->font.strikeoutThickness); } else PSDRV_WriteRectangle(physDev, x, y - physDev->font.strikeoutPosition, sz.cx, physDev->font.strikeoutThickness); PSDRV_WriteFill(physDev); if (escapement != 0) /* rotated text */ PSDRV_WriteGRestore(physDev); /* restore the graphics state */ } } if(glyphs && glyphs != str) HeapFree(GetProcessHeap(), 0, glyphs); return TRUE; }