FW: [resend] notepad: Improve printing considerably

Rolf Kalbermatter r.kalbermatter at hccnet.nl
Fri Apr 6 12:50:37 CDT 2007


 
Changelog
  programs/notepad/dialog.c
  programs/notepad/main.c
  programs/notepad/main.h
    Improve printing considerably!
    - Factorize the printing function to keep it more readable
    - 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.

License: X11/LGPL

Rolf Kalbermatter
-------------- next part --------------
>From d2674344d88fe80ce05a842e3e5c406eab45ed3d Mon Sep 17 00:00:00 2001
From: Rolf Kalbermatter <r.kalbermatter at hccnet.nl>
Date: Fri, 6 Apr 2007 10:39:20 +0200
Subject: [PATCH] Improve printing considerably
---
 programs/notepad/dialog.c |  294 ++++++++++++++++++++++++++++-----------------
 programs/notepad/main.c   |    2 
 programs/notepad/main.h   |    1 
 3 files changed, 188 insertions(+), 109 deletions(-)

diff --git a/programs/notepad/dialog.c b/programs/notepad/dialog.c
index f220293..d5bc84e 100644
--- a/programs/notepad/dialog.c
+++ b/programs/notepad/dialog.c
@@ -4,6 +4,7 @@
  *  Copyright 1998,99 Marcel Baur <mbaur at g26.ethz.ch>
  *  Copyright 2002 Sylvain Petreolle <spetreolle at yahoo.fr>
  *  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 "main.h"
 #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;
-            
+
+    if (StartDoc(printer.hDC, &di) > 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 {
-                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<SPACES_IN_TAB; m++) {
-                            if (k <  PRINT_LEN_MAX)
-                                cTemp[k++] = ' ';
-                        }
-                    }
-                    else if (k <  PRINT_LEN_MAX)
-                        cTemp[k++] = pTemp[i];
-                    i++;
-                }
-                if (dopage)
-                    TextOut(printer.hDC, xLeft, yTop, cTemp, k);
-                /* find the next line */
-                while (i < size && (pTemp[i] == '\n' || pTemp[i] == '\r')) {
-                    if (pTemp[i] == '\n')
-                        yTop += szMetric.cy;
-                    i++;
+                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;
                 }
-            } while (i<size && yTop<(cHeightPels-border*2));
-                
-            if (dopage)
-                EndPage(printer.hDC);
-            pagecount++;
-        } while (i<size);
-    }
-    SelectObject(printer.hDC, old_font);
+                else
+                    dopage = 1;
+
+                ret = notepad_print_page(printer.hDC, &rc, dopage, page, &tInfo);
+                page++;
+            } while (ret && tInfo.mptr < tInfo.mend);
 
-    EndDoc(printer.hDC);
+            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 6bd6ed8..c7b961f 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 e37062b..51db639 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);
-- 
1.4.1



More information about the wine-patches mailing list