From 5eb6c11aba740869f7363f7b4444e5f763937d9f Mon Sep 17 00:00:00 2001 From: Rolf Kalbermatter Date: Fri, 6 Apr 2007 19:50:37 +0200 Subject: [PATCH] notepad: Improve printing considerably. Make fonts and the other measurements the correct size in relation to the actual printer resolution instead of thinking it uses the same resolution as the display. Before fixed sized (and for most printer resolutions way to small) margins where used and the font size was taken directly from the screen font independent of the actual printer resolution, resulting in a completely unreadable micro text on most printouts. --- programs/notepad/dialog.c | 296 ++++++++++++++++++++++++-------------- programs/notepad/main.c | 2 +- programs/notepad/main.h | 1 + 3 files changed, 189 insertions(+), 110 deletions(-) diff --git a/programs/notepad/dialog.c b/programs/notepad/dialog.c index f2202933eab..c5cfc3cb466 100644 --- a/programs/notepad/dialog.c +++ b/programs/notepad/dialog.c @@ -4,6 +4,7 @@ * Copyright 1998,99 Marcel Baur * Copyright 2002 Sylvain Petreolle * Copyright 2002 Andriy Palamarchuk + * Copyright 2007 Rolf Kalbermatter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,7 +33,7 @@ #include "dialog.h" #define SPACES_IN_TAB 8 -#define PRINT_LEN_MAX 120 +#define PRINT_LEN_MAX 500 static const WCHAR helpfileW[] = { 'n','o','t','e','p','a','d','.','h','l','p',0 }; @@ -367,40 +368,139 @@ VOID DIALOG_FileSaveAs(VOID) } } +typedef struct { + LPWSTR mptr; + LPWSTR mend; + LPWSTR lptr; + DWORD len; +} TEXTINFO, *LPTEXTINFO; + +static int notepad_print_header(HDC hdc, RECT *rc, BOOL dopage, BOOL header, int page, LPWSTR text) +{ + SIZE szMetric; + + if (*text) + { + /* Write the header or footer */ + GetTextExtentPoint32(hdc, text, lstrlen(text), &szMetric); + if (dopage) + ExtTextOut(hdc, (rc->left + rc->right - szMetric.cx) / 2, + header ? rc->top : rc->bottom - szMetric.cy, + ETO_CLIPPED, rc, text, lstrlen(text), NULL); + return 1; + } + return 0; +} + +static BOOL notepad_print_page(HDC hdc, RECT *rc, BOOL dopage, int page, LPTEXTINFO tInfo) +{ + int b, y; + TEXTMETRIC tm; + SIZE szMetrics; + + if (dopage) + { + if (StartPage(hdc) <= 0) + { + static const WCHAR failedW[] = { 'S','t','a','r','t','P','a','g','e',' ','f','a','i','l','e','d',0 }; + static const WCHAR errorW[] = { 'P','r','i','n','t',' ','E','r','r','o','r',0 }; + MessageBox(Globals.hMainWnd, failedW, errorW, MB_ICONEXCLAMATION); + return FALSE; + } + } + + GetTextMetrics(hdc, &tm); + y = rc->top + notepad_print_header(hdc, rc, dopage, TRUE, page, Globals.szFileName) * tm.tmHeight; + b = rc->bottom - 2 * notepad_print_header(hdc, rc, FALSE, FALSE, page, Globals.szFooter) * tm.tmHeight; + + do { + INT m, n; + + if (!tInfo->len) + { + /* find the end of the line */ + while (tInfo->mptr < tInfo->mend && *tInfo->mptr != '\n' && *tInfo->mptr != '\r') + { + if (*tInfo->mptr == '\t') + { + /* replace tabs with spaces */ + for (m = 0; m < SPACES_IN_TAB; m++) + { + if (tInfo->len < PRINT_LEN_MAX) + tInfo->lptr[tInfo->len++] = ' '; + else if (Globals.bWrapLongLines) + break; + } + } + else if (tInfo->len < PRINT_LEN_MAX) + tInfo->lptr[tInfo->len++] = *tInfo->mptr; + + if (tInfo->len >= PRINT_LEN_MAX && Globals.bWrapLongLines) + break; + + tInfo->mptr++; + } + } + + /* Find out how much we should print if line wrapping is enabled */ + if (Globals.bWrapLongLines) + { + GetTextExtentExPoint(hdc, tInfo->lptr, tInfo->len, rc->right - rc->left, &n, NULL, &szMetrics); + if (n < tInfo->len && tInfo->lptr[n] != ' ') + { + m = n; + /* Don't wrap words unless it's a single word over the entire line */ + while (m && tInfo->lptr[m] != ' ') m--; + if (m > 0) n = m + 1; + } + } + else + n = tInfo->len; + + if (dopage) + ExtTextOut(hdc, rc->left, y, ETO_CLIPPED, rc, tInfo->lptr, n, NULL); + + tInfo->len -= n; + + if (tInfo->len) + { + memcpy(tInfo->lptr, tInfo->lptr + n, tInfo->len * sizeof(WCHAR)); + y += tm.tmHeight + tm.tmExternalLeading; + } + else + { + /* find the next line */ + while (tInfo->mptr < tInfo->mend && y < b && (*tInfo->mptr == '\n' || *tInfo->mptr == '\r')) + { + if (*tInfo->mptr == '\n') + y += tm.tmHeight + tm.tmExternalLeading; + tInfo->mptr++; + } + } + } while (tInfo->mptr < tInfo->mend && y < b); + + notepad_print_header(hdc, rc, dopage, FALSE, page, Globals.szFooter); + if (dopage) + { + EndPage(hdc); + } + return TRUE; +} + VOID DIALOG_FilePrint(VOID) { DOCINFO di; PRINTDLG printer; - SIZE szMetric; - int cWidthPels, cHeightPels, border; - int xLeft, yTop, pagecount, dopage, copycount; - unsigned int i; - LOGFONT hdrFont; - HFONT font, old_font=0; + int page, dopage, copy; + LOGFONT lfFont; + HFONT hTextFont, old_font = 0; DWORD size; + BOOL ret = FALSE; + RECT rc; LPWSTR pTemp; + TEXTINFO tInfo; WCHAR cTemp[PRINT_LEN_MAX]; - static const WCHAR print_fontW[] = { 'C','o','u','r','i','e','r',0 }; - static const WCHAR letterM[] = { 'M',0 }; - /* Get a small font and print some header info on each page */ - hdrFont.lfHeight = -35; - hdrFont.lfWidth = 0; - hdrFont.lfEscapement = 0; - hdrFont.lfOrientation = 0; - hdrFont.lfWeight = FW_BOLD; - hdrFont.lfItalic = 0; - hdrFont.lfUnderline = 0; - hdrFont.lfStrikeOut = 0; - hdrFont.lfCharSet = ANSI_CHARSET; - hdrFont.lfOutPrecision = OUT_DEFAULT_PRECIS; - hdrFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; - hdrFont.lfQuality = PROOF_QUALITY; - hdrFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN; - lstrcpy(hdrFont.lfFaceName, print_fontW); - - font = CreateFontIndirect(&hdrFont); - /* Get Current Settings */ ZeroMemory(&printer, sizeof(printer)); printer.lStructSize = sizeof(printer); @@ -408,7 +508,7 @@ VOID DIALOG_FilePrint(VOID) printer.hDevMode = Globals.hDevMode; printer.hDevNames = Globals.hDevNames; printer.hInstance = Globals.hInstance; - + /* Set some default flags */ printer.Flags = PD_RETURNDC | PD_NOSELECTION; printer.nFromPage = 0; @@ -424,7 +524,7 @@ VOID DIALOG_FilePrint(VOID) Globals.hDevMode = printer.hDevMode; Globals.hDevNames = printer.hDevNames; - assert(printer.hDC != 0); + SetMapMode(printer.hDC, MM_TEXT); /* initialize DOCINFO */ di.cbSize = sizeof(DOCINFO); @@ -433,94 +533,72 @@ VOID DIALOG_FilePrint(VOID) di.lpszDatatype = NULL; di.fwType = 0; - if (StartDoc(printer.hDC, &di) <= 0) return; - - /* Get the page dimensions in pixels. */ - cWidthPels = GetDeviceCaps(printer.hDC, HORZRES); - cHeightPels = GetDeviceCaps(printer.hDC, VERTRES); - /* Get the file text */ size = GetWindowTextLength(Globals.hEdit) + 1; pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); if (!pTemp) { - ShowLastError(); - return; + DeleteDC(printer.hDC); + ShowLastError(); + return; } size = GetWindowText(Globals.hEdit, pTemp, size); - - border = 150; - old_font = SelectObject(printer.hDC, Globals.hFont); - GetTextExtentPoint32(printer.hDC, letterM, 1, &szMetric); - for (copycount=1; copycount <= printer.nCopies; copycount++) { - i = 0; - pagecount = 1; - do { - if (printer.Flags & PD_PAGENUMS) { - /* a specific range of pages is selected, so - * skip pages that are not to be printed - */ - if (pagecount > printer.nToPage) - break; - else if (pagecount >= printer.nFromPage) - dopage = 1; - else - dopage = 0; - } - else - dopage = 1; - - if (dopage) { - if (StartPage(printer.hDC) <= 0) { - static const WCHAR failedW[] = { 'S','t','a','r','t','P','a','g','e',' ','f','a','i','l','e','d',0 }; - static const WCHAR errorW[] = { 'P','r','i','n','t',' ','E','r','r','o','r',0 }; - MessageBox(Globals.hMainWnd, failedW, errorW, MB_ICONEXCLAMATION); - return; - } - /* Write a rectangle and header at the top of each page */ - SelectObject(printer.hDC, font); - Rectangle(printer.hDC, border, border, cWidthPels-border, border+szMetric.cy*2); - TextOut(printer.hDC, border*2, border+szMetric.cy/2, Globals.szFileTitle, lstrlen(Globals.szFileTitle)); - } - - SelectObject(printer.hDC, Globals.hFont); - /* The starting point for the main text */ - xLeft = border; - yTop = border+szMetric.cy*4; - - do { - int k=0, m; - /* find the end of the line */ - while (i < size && pTemp[i] != '\n' && pTemp[i] != '\r') { - if (pTemp[i] == '\t') { - /* replace tabs with spaces */ - for (m=0; m 0) + { + /* Get the page margins in pixels. */ + rc.top = MulDiv(Globals.iMarginTop, GetDeviceCaps(printer.hDC, LOGPIXELSY), 2540) - + GetDeviceCaps(printer.hDC, PHYSICALOFFSETY); + rc.bottom = GetDeviceCaps(printer.hDC, PHYSICALHEIGHT) - + MulDiv(Globals.iMarginBottom, GetDeviceCaps(printer.hDC, LOGPIXELSY), 2540); + rc.left = MulDiv(Globals.iMarginLeft, GetDeviceCaps(printer.hDC, LOGPIXELSX), 2540) - + GetDeviceCaps(printer.hDC, PHYSICALOFFSETX); + rc.right = GetDeviceCaps(printer.hDC, PHYSICALWIDTH) - + MulDiv(Globals.iMarginRight, GetDeviceCaps(printer.hDC, LOGPIXELSX), 2540); + + /* Create a font for the printer resolution */ + lfFont = Globals.lfFont; + lfFont.lfHeight = MulDiv(lfFont.lfHeight, GetDeviceCaps(printer.hDC, LOGPIXELSY), get_dpi()); + /* Make the font a bit lighter */ + lfFont.lfWeight -= 100; + hTextFont = CreateFontIndirect(&lfFont); + old_font = SelectObject(printer.hDC, hTextFont); + + for (copy = 1; copy <= printer.nCopies; copy++) + { + page = 1; + + tInfo.mptr = pTemp; + tInfo.mend = pTemp + size; + tInfo.lptr = cTemp; + tInfo.len = 0; + + do { + if (printer.Flags & PD_PAGENUMS) + { + /* a specific range of pages is selected, so + * skip pages that are not to be printed + */ + if (page > printer.nToPage) + break; + else if (page >= printer.nFromPage) + dopage = 1; + else + dopage = 0; + } + else + dopage = 1; + + ret = notepad_print_page(printer.hDC, &rc, dopage, page, &tInfo); + page++; + } while (ret && tInfo.mptr < tInfo.mend); + + if (!ret) break; + } + EndDoc(printer.hDC); + SelectObject(printer.hDC, old_font); + DeleteObject(hTextFont); + } DeleteDC(printer.hDC); HeapFree(GetProcessHeap(), 0, pTemp); } diff --git a/programs/notepad/main.c b/programs/notepad/main.c index 6bd6ed84cca..c7b961f43e6 100644 --- a/programs/notepad/main.c +++ b/programs/notepad/main.c @@ -81,7 +81,7 @@ VOID SetFileName(LPCWSTR szFileName) * * Get the dpi from registry HKCC\Software\Fonts\LogPixels. */ -static DWORD get_dpi(void) +DWORD get_dpi(void) { static const WCHAR dpi_key_name[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'}; static const WCHAR dpi_value_name[] = {'L','o','g','P','i','x','e','l','s','\0'}; diff --git a/programs/notepad/main.h b/programs/notepad/main.h index e37062b3c59..51db639dfda 100644 --- a/programs/notepad/main.h +++ b/programs/notepad/main.h @@ -55,3 +55,4 @@ extern NOTEPAD_GLOBALS Globals; VOID SetFileName(LPCWSTR szFileName); void NOTEPAD_DoFind(FINDREPLACE *fr); +DWORD get_dpi(void);