DISPLAY.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:33k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1992-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /**************************************************************************
  11. *  display.c -- module for the window with the test font.
  12. *   Includes the window procedure and an initialization routine.
  13. *
  14. * store the handle to the test font in the extra bytes of this window.
  15. *
  16. *
  17. * HORZ_SCROLL used to step through UC ranges when in "all glyphs" mode.
  18. * VERT_SCROLL:
  19. *   scroll bar range is the total number of lines needed for all glyphs
  20. *    minus the number which may be shown in the window.
  21. *   scroll bar position is then the first line which is to be drawn.
  22. *
  23. *
  24. *
  25. **************************************************************************/
  26. #include <windows.h>
  27. #include <string.h>
  28. #include "ttfonts.h"
  29. /* defines for the gridding pattern in background of window */
  30. #define GRIDCOLOR  PALETTEINDEX (3)
  31. #define TICKSPACE  10
  32. /* global variables store the start and end codepoints for UC ranges. */
  33. USHORT *endCount= NULL;
  34. USHORT *startCount= NULL;
  35. int CountUCSegments (HDC);
  36. /* error return value from CountUCSegments */
  37. #define SEGMENTERROR -1
  38. HWND   hwndFaceBanner;
  39. TCHAR szHello[] = TEXT("Hello");
  40. VOID BlamGlyphs (HDC, PTEXTMETRIC, USHORT, USHORT, PRECT, BOOL);
  41. int initDisplay(HWND hwndParent)
  42. {
  43. WNDCLASS  wc;
  44.   wc.style = CS_VREDRAW | CS_HREDRAW;
  45.   wc.lpfnWndProc = (WNDPROC)DisplayWndProc;
  46.   wc.cbClsExtra = 0;
  47.   wc.cbWndExtra = 0;
  48.   wc.hInstance = hInst;
  49.   wc.hIcon = LoadIcon(hInst, TEXT("ttfontsIcon"));
  50.   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  51.   wc.hbrBackground = NULL;
  52.   wc.lpszMenuName = NULL;
  53.   wc.lpszClassName = TEXT("display");
  54.   if (!RegisterClass(&wc)) return (FALSE);
  55.   hwndDisplay = CreateMDIWindow(
  56.       TEXT("display"),
  57.       TEXT("Display"),
  58.       WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_VISIBLE |
  59.                  WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_VSCROLL | WS_HSCROLL,
  60.       CHILDLEFT(2),
  61.       CHILDTOP,
  62.       GetSystemMetrics (SM_CXFULLSCREEN)/3 - 10,
  63.       GetSystemMetrics (SM_CYFULLSCREEN)/3,
  64.       hwndParent, hInst, 0);
  65.   /* create child window to display face name */
  66.   hwndFaceBanner = CreateWindow(
  67.         TEXT("STATIC"), TEXT(""),
  68.         WS_CHILD | WS_VISIBLE | WS_BORDER,
  69.         -1,0,
  70.         GetSystemMetrics (SM_CXFULLSCREEN),
  71.         GetSystemMetrics (SM_CYMENU),
  72.         hwndDisplay, NULL, hInst, NULL);
  73.   if (!hwndDisplay) return (FALSE);
  74.   return TRUE;
  75. }
  76. /**************************************************************************
  77. *
  78. *  function:  DisplayWndProc()
  79. *
  80. *  input parameters:  normal window procedure parameters.
  81. *
  82. *  global variables:
  83. *   gDisplaymode - menu state
  84. **************************************************************************/
  85. LRESULT CALLBACK DisplayWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  86. {
  87. static HANDLE hPenGrid;
  88. static LPLOGFONT     lplf;
  89. static LPTEXTMETRIC  lptm;
  90. static HFONT  hfont;
  91. static HDC    hdcStatic;  /* Sent to other window procedures. */
  92. static HDC hdc;
  93. static RECT rect;
  94. static int min, max;
  95. static TEXTMETRIC tm;
  96. static int iSeg;
  97. static TCHAR buffer[100];
  98. static int nCharPerLine, nTotalGlyphs, lineHeight;
  99. static int nLinesTotal, nLinesWindow, nLinesDifference;
  100. static int scrollRangeHigh, topLineShowing;
  101. int i;
  102.   switch (message) {
  103.     /**********************************************************************
  104.     *  WMU_DEMOTOLF
  105.     *
  106.     *  lParam - pointer to LOGFONT structure.
  107.     *
  108.     * User message.  Fill up the display LOGFONT from the HFONT
  109.     *  in the extra bytes.
  110.     **********************************************************************/
  111.     case WMU_DEMOTOLF: {
  112.       lplf = (LPLOGFONT) lParam;
  113.       hfont = (HFONT) GetWindowLong (hwnd, GWL_USERDATA);
  114.       GetObject (hfont, sizeof(LOGFONT), lplf);
  115.     } return 0;
  116.     /**********************************************************************
  117.     *  WMU_DEMOTOTM
  118.     *
  119.     *  lParam - pointer to TEXTMETRIC structure.
  120.     *
  121.     * User message.  Fill up the TEXTMETRIC from the HFONT
  122.     *  in the extra bytes.
  123.     **********************************************************************/
  124.     case WMU_DEMOTOTM: {
  125.       lptm = (LPTEXTMETRIC) lParam;
  126.       hfont = (HFONT) GetWindowLong (hwnd, GWL_USERDATA);
  127.       hdc = GetDC (hwnd);
  128.       SelectObject (hdc,hfont);
  129.       GetTextMetrics (hdc, lptm);
  130.       ReleaseDC (hwnd, hdc);
  131.     } return 0;
  132.     /**********************************************************************
  133.     *  WMU_DEMOGETDC
  134.     *
  135.     * User message.  Return an HDC.
  136.     **********************************************************************/
  137.     case WMU_DEMOGETDC: {
  138.       hfont = (HFONT) GetWindowLong (hwnd, GWL_USERDATA);
  139.       hdcStatic = GetDC (hwnd);
  140.       SelectObject (hdcStatic,hfont);
  141.       return (LRESULT)hdcStatic;
  142.     } break;
  143.     /**********************************************************************
  144.     *  WMU_DEMORELEASEDC
  145.     *
  146.     *  lParam - the same HDC returned by WMU_DEMOGETDC
  147.     *
  148.     * User message.  Release the HDC.
  149.     **********************************************************************/
  150.     case WMU_DEMORELEASEDC: {
  151.       hdcStatic = (HDC) lParam;
  152.       ReleaseDC (hwnd, hdcStatic);
  153.     } return 0;
  154.     /**********************************************************************
  155.     *  WMU_HFONTTODEMO
  156.     *
  157.     *  lParam - hFont
  158.     *
  159.     * User message.  Use the input HFONT to set a new
  160.     *  font for this window.  Store the new font in the HFONT extra bytes.
  161.     **********************************************************************/
  162.     case WMU_HFONTTODEMO: {
  163.       /* Get and delete the last font placed in this window. */
  164.       hfont = (HFONT) GetWindowLong (hwnd, GWL_USERDATA);
  165.       DeleteObject (hfont);
  166.       hfont = (HFONT) lParam;
  167.       SetWindowLong (hwnd, GWL_USERDATA, (LONG) hfont);
  168.       /* make sure that scroll metrics are ok */
  169.       switch (gDisplaymode) {
  170.         case IDM_MODEHELLO:   SendMessage (hwnd, WMU_NEWMODEHELLO, 0,0);
  171.           break;
  172.         case IDM_MODETMRANGE: SendMessage (hwnd, WMU_NEWMODETMRANGE, 0,0);
  173.           break;
  174.         case IDM_MODEALL:
  175.           if (!SendMessage (hwndDisplay, WMU_NEWMODEALL, 0,0)) {
  176.             MessageBox (NULL, szResetDisplay, szMBERROR, MBERRORFLAGS);
  177.             SendMessage (hwndMain, WM_COMMAND, IDM_MODEHELLO, 0);
  178.             return 0;
  179.           }
  180.           break;
  181.       } /* end switch */
  182.       InvalidateRect (hwnd, NULL, TRUE);
  183.     } return 0;
  184.     /**********************************************************************
  185.     *  WMU_NEWFONT
  186.     *
  187.     *  lParam - pointer to LOGFONT structure.
  188.     *
  189.     * User message.  Use the input LOGFONT structure to create a new
  190.     *  font for this window.  Send a WMU_HFONTTODEMO message to set the
  191.     *  font into the extra bytes for the window.
  192.     **********************************************************************/
  193.     case WMU_NEWFONT: {
  194.       lplf = (LPLOGFONT) lParam;
  195.       /* Create a new logical font and set it into the windows extra bytes. */
  196.       hfont = CreateFontIndirect (lplf);
  197.       SendMessage (hwnd, WMU_HFONTTODEMO, 0, (LPARAM) hfont);
  198.     } return 0;
  199.     /**********************************************************************
  200.     *  WM_CREATE
  201.     *
  202.     * Create pens for drawing with later.
  203.     **********************************************************************/
  204.     case WM_CREATE:
  205.       hPenGrid   = CreatePen (PS_SOLID, 1, GRIDCOLOR);
  206.       SetWindowLong (hwnd, GWL_USERDATA, (LONG) GetStockObject (SYSTEM_FONT));
  207.     break;
  208.     /**********************************************************************
  209.     *  WM_DESTROY
  210.     *
  211.     * Complement of the WM_CREATE message.  Delete the pens that were
  212.     *  created, free startCount, endCount arrays.
  213.     *
  214.     **********************************************************************/
  215.     case WM_DESTROY:
  216.       DeleteObject (hPenGrid);
  217.       if (startCount != NULL) LocalFree (LocalHandle (startCount));
  218.       if (endCount != NULL) LocalFree (LocalHandle (endCount));
  219.     break;
  220.     /**********************************************************************
  221.     *  WM_ERASEBKGND
  222.     *
  223.     * Offset the origin conditional on gDisplaymode.  Grid the window.
  224.     **********************************************************************/
  225.     case WM_ERASEBKGND: {
  226.       HDC hdc;
  227.       RECT rect;
  228.       int i;
  229.       hdc = (HDC)wParam;
  230.       GetClientRect (hwnd, &rect);
  231.       FillRect (hdc, &rect, GetStockObject (LTGRAY_BRUSH));
  232.       if (gDisplaymode == IDM_MODEHELLO) {
  233.         SetViewportOrgEx (hdc, rect.right /2, rect.bottom/2, NULL);
  234.         OffsetRect (&rect, -rect.right/2, -rect.bottom/2);
  235.         SelectObject(hdc, hPenGrid);
  236.         /* Draw vertical lines.  */
  237.         for (i = 0; i<= rect.right; i+=TICKSPACE){
  238.           MoveToEx (hdc, i, rect.top, NULL);
  239.           LineTo (hdc, i, rect.bottom);
  240.           MoveToEx (hdc, -i, rect.top, NULL);
  241.           LineTo (hdc, -i, rect.bottom);
  242.         }
  243.         MoveToEx (hdc, 1, rect.top, NULL);
  244.         LineTo (hdc, 1, rect.bottom);
  245.         /* Draw horizontal lines.  */
  246.         for (i = 0; i<= rect.bottom; i+=TICKSPACE){
  247.           MoveToEx (hdc, rect.left,i, NULL);
  248.           LineTo (hdc, rect.right,i);
  249.           MoveToEx (hdc, rect.left,-i, NULL);
  250.           LineTo (hdc, rect.right,-i);
  251.         }
  252.         MoveToEx (hdc, rect.left, 1, NULL);
  253.         LineTo (hdc, rect.right,1);
  254.       }
  255.     } return TRUE;
  256.     /**********************************************************************
  257.     *  WM_VSCROLL
  258.     *
  259.     * Slide the contents of the window up and down.  Notice that the
  260.     *  scroll bar thumb position is important for painting.
  261.     **********************************************************************/
  262.     case WM_VSCROLL:
  263.       switch (LOWORD(wParam)){
  264.         int OldPos, NewPos;
  265.         case SB_PAGEDOWN:
  266.         case SB_LINEDOWN:
  267.           OldPos = GetScrollPos (hwnd, SB_VERT);
  268.           SetScrollPos (hwnd, SB_VERT, (OldPos+1), TRUE);
  269.           NewPos = GetScrollPos (hwnd, SB_VERT);
  270.           ScrollWindow (hwnd, 0,(OldPos-NewPos)*lineHeight, NULL, NULL);
  271.         break;
  272.         case SB_PAGEUP:
  273.         case SB_LINEUP:
  274.           OldPos = GetScrollPos (hwnd, SB_VERT);
  275.           SetScrollPos (hwnd, SB_VERT, (OldPos-1), TRUE);
  276.           NewPos = GetScrollPos (hwnd, SB_VERT);
  277.           ScrollWindow (hwnd, 0,(OldPos-NewPos)*lineHeight, NULL, NULL);
  278.         break;
  279.         case SB_THUMBPOSITION:
  280.           OldPos = GetScrollPos (hwnd, SB_VERT);
  281.           NewPos = HIWORD (wParam);
  282.           SetScrollPos (hwnd, SB_VERT, NewPos, TRUE);
  283.           ScrollWindow (hwnd, 0, (OldPos-NewPos)*lineHeight, NULL, NULL);
  284.         break;
  285.       }
  286.     break;
  287.     /**********************************************************************
  288.     *  WM_HSCROLL
  289.     *
  290.     * The horz scroll should only be present when in MODEALL.
  291.     * Step through the allglyphs ranges.
  292.     * In every case, inform the window the range has changed,
  293.     *  and invalidate it to force a repaint.
  294.     **********************************************************************/
  295.     case WM_HSCROLL:
  296.       switch (LOWORD(wParam)){
  297.         int OldPos, NewPos;
  298.         case SB_PAGEDOWN:
  299.         case SB_LINEDOWN:
  300.           OldPos = GetScrollPos (hwnd, SB_HORZ);
  301.           SetScrollPos (hwnd, SB_HORZ, (OldPos+1), TRUE);
  302.           SendMessage (hwnd,WMU_NEWMODE_NEWSEG, 0,0);
  303.           InvalidateRect (hwnd, NULL, TRUE);
  304.         break;
  305.         case SB_PAGEUP:
  306.         case SB_LINEUP:
  307.           OldPos = GetScrollPos (hwnd, SB_HORZ);
  308.           SetScrollPos (hwnd, SB_HORZ, (OldPos-1), TRUE);
  309.           SendMessage (hwnd,WMU_NEWMODE_NEWSEG, 0,0);
  310.           InvalidateRect (hwnd, NULL, TRUE);
  311.         break;
  312.         case SB_THUMBPOSITION:
  313.           OldPos = GetScrollPos (hwnd, SB_HORZ);
  314.           NewPos = HIWORD (wParam);
  315.           SetScrollPos (hwnd, SB_HORZ, NewPos, TRUE);
  316.           SendMessage (hwnd,WMU_NEWMODE_NEWSEG, 0,0);
  317.           InvalidateRect (hwnd, NULL, TRUE);
  318.         break;
  319.       }
  320.     break;
  321.     /**********************************************************************
  322.     * WMU_NEWMODEALL
  323.     *
  324.     *   returns - TRUE if a scalable font file.
  325.     *             FALSE if GetFontData fails.
  326.     *
  327.     * This message is sent one time when the user checks "Show all glyphs."
  328.     *  Here we set up the horizontal scroll bar, and the start/endCount arrays.
  329.     **********************************************************************/
  330.     case WMU_NEWMODEALL: {
  331.       HDC hdc;
  332.       int nSegments;
  333.       SetCursor (LoadCursor (NULL, IDC_WAIT));
  334.       hdc = GetDC(hwnd);
  335.       hfont = (HFONT) GetWindowLong (hwnd, GWL_USERDATA);
  336.       SelectObject (hdc,hfont);
  337.       nSegments = CountUCSegments (hdc); /* slow computation */
  338.       ReleaseDC (hwnd, hdc);
  339.       SetCursor (LoadCursor (NULL, IDC_ARROW));
  340.       if (nSegments == SEGMENTERROR) return FALSE;
  341.       gDisplaymode =IDM_MODEALL;
  342.       ShowWindow (hwndFaceBanner, SW_HIDE);
  343.       SetScrollRange (hwnd, SB_HORZ, 0, (nSegments-1), TRUE);
  344.       SetScrollPos (hwnd, SB_HORZ, 0, TRUE);
  345.       SendMessage (hwndDisplay, WMU_NEWMODE_NEWSEG, 0,0);
  346.       return TRUE;
  347.     } break;
  348.     /**********************************************************************
  349.     *  WMU_NEWMODEHELLO
  350.     *  WMU_NEWMODETMRANGE
  351.     *  WMU_NEWMODE_NEWSEG
  352.     *
  353.     *
  354.     * Sent every time an event occurs which will change the layout of
  355.     *  the display glyphs.  I.e.
  356.     *       window resized.
  357.     *       display mode switch
  358.     *       allglyph display mode, next range
  359.     *
  360.     * Be careful because the SetScrollRange() may cause a new WM_SIZE
  361.     *  which in turn will cause this message to be resent.
  362.     *
  363.     **********************************************************************/
  364.     case WMU_NEWMODEHELLO:
  365.       /* Set the window title text. */
  366.       SetWindowText (hwnd, TEXT("Display"));
  367.       gDisplaymode =IDM_MODEHELLO;
  368.       ShowWindow (hwndFaceBanner, SW_SHOW);
  369.       SetScrollRange (hwnd, SB_HORZ, 0, 0, TRUE);
  370.       SetScrollRange (hwnd, SB_VERT, 0, 0, TRUE);
  371.     break;
  372.     case WMU_NEWMODETMRANGE: {
  373.       /* Set the window title text. */
  374.       SetWindowText (hwnd, TEXT("Display [tmFirstChar, tmLastChar]"));
  375.       gDisplaymode =IDM_MODETMRANGE;
  376.       ShowWindow (hwndFaceBanner, SW_HIDE);
  377.       SetScrollRange (hwnd, SB_HORZ, 0, 0, TRUE);
  378.       hdc = GetDC(hwnd);
  379.       GetClientRect (hwnd, &rect);
  380.       /* subtract off the scroll width if it is NOT there.
  381.        *  (if it is, it will be automatically excluded by GetClientRect)
  382.        *  if it is not there, it may be added, and we want space for it.
  383.        */
  384.       GetScrollRange (hwnd, SB_VERT, &min, &max);
  385.       if (min == max) rect.right -= GetSystemMetrics (SM_CXVSCROLL);
  386.       /* select the font into the window to get text metrics for. */
  387.       hfont = (HFONT) GetWindowLong (hwnd, GWL_USERDATA);
  388.       SelectObject (hdc,hfont);
  389.       GetTextMetrics (hdc, &tm);
  390.       nCharPerLine = rect.right / tm.tmAveCharWidth;
  391.       nTotalGlyphs = tm.tmLastChar-tm.tmFirstChar;
  392.       lineHeight = tm.tmHeight + tm.tmExternalLeading;
  393.       nLinesTotal = nTotalGlyphs / nCharPerLine;
  394.       nLinesWindow = rect.bottom / lineHeight;
  395.       nLinesDifference = nLinesTotal - nLinesWindow;
  396.       scrollRangeHigh = nLinesTotal - nLinesWindow;
  397.       /* reset the scroll bar range.  If there is no need for one,
  398.        *  then set the position to 0, and the range to 0,0 and it
  399.        *  will not be visisble.
  400.        */
  401.       if (nLinesDifference >0) {
  402.         SetScrollRange (hwnd, SB_VERT, 0, (nLinesDifference +1), TRUE);
  403.       } else {
  404.         SetScrollPos (hwnd, SB_VERT, 0, TRUE);
  405.         SetScrollRange (hwnd, SB_VERT, 0, 0, TRUE);
  406.       }
  407.       ReleaseDC (hwnd, hdc);
  408.     } return FALSE;
  409.     case WMU_NEWMODE_NEWSEG: {
  410.       gDisplaymode =IDM_MODEALL;
  411.       SetScrollPos (hwnd, SB_VERT, 0, TRUE);
  412.       hdc = GetDC(hwnd);
  413.       GetClientRect (hwnd, &rect);
  414.       /* subtract off the scroll width if it is NOT there.
  415.        *  (if it is, it will be automatically excluded by GetClientRect)
  416.        *  if it is not there, it may be added, and we want space for it.
  417.        */
  418.       GetScrollRange (hwnd, SB_VERT, &min, &max);
  419.       if (min == max) rect.right -= GetSystemMetrics (SM_CXVSCROLL);
  420.       /* select the font into the window to get text metrics for. */
  421.       hfont = (HFONT) GetWindowLong (hwnd, GWL_USERDATA);
  422.       SelectObject (hdc,hfont);
  423.       GetTextMetrics (hdc, &tm);
  424.       iSeg = GetScrollPos (hwnd, SB_HORZ);
  425.       /* Set the window title text to show display range. */
  426.       wsprintf (buffer, TEXT("Display [%04x, %04x]"),
  427.                                   (int)startCount[iSeg],
  428.                                   (int)endCount[iSeg]);
  429.       SetWindowText (hwnd, buffer);
  430.       nTotalGlyphs = endCount[iSeg] - startCount[iSeg];
  431.       nCharPerLine = rect.right / tm.tmAveCharWidth;
  432.       nLinesTotal = nTotalGlyphs / nCharPerLine;
  433.       lineHeight = tm.tmHeight + tm.tmExternalLeading;
  434.       nLinesWindow = rect.bottom / lineHeight;
  435.       nLinesDifference = nLinesTotal - nLinesWindow;
  436.       scrollRangeHigh = nLinesTotal - nLinesWindow;
  437.       /* reset the scroll bar range.  If there is no need for one,
  438.        *  then set the position to 0, and the range to 0,0 and it
  439.        *  will not be visisble.
  440.        */
  441.       if (nLinesDifference >0) {
  442.         SetScrollRange (hwnd, SB_VERT, 0, (nLinesDifference +1), FALSE);
  443.       } else {
  444.         SetScrollPos (hwnd, SB_VERT, 0, TRUE);
  445.         SetScrollRange (hwnd, SB_VERT, 0, 0, TRUE);
  446.       }
  447.       ReleaseDC (hwnd, hdc);
  448.     } return FALSE;
  449.     /**********************************************************************
  450.     *  WM_SIZE
  451.     *
  452.     **********************************************************************/
  453.     case WM_SIZE:
  454.       /* make sure that scroll metrics are ok */
  455.       switch (gDisplaymode) {
  456.         case IDM_MODEHELLO:   SendMessage (hwnd, WMU_NEWMODEHELLO, 0,0);
  457.           break;
  458.         case IDM_MODETMRANGE: SendMessage (hwnd, WMU_NEWMODETMRANGE, 0,0);
  459.           break;
  460.         case IDM_MODEALL:     SendMessage (hwnd, WMU_NEWMODE_NEWSEG, 0,0);
  461.           break;
  462.       } /* end switch */
  463.     break;  /* fall through to MDIChildProc */
  464.     /**********************************************************************
  465.     *  WM_PAINT
  466.     *
  467.     * Offset the origin conditional on gDisplaymode.  Write the "Hello"
  468.     *  string, or step though all of the glyphs (from TEXTMETRIC.tmFirstChar
  469.     *  to TEXTMETRIC.tmLastChar), or paint all of the glyphs in the UC segment.
  470.     **********************************************************************/
  471.     case WM_PAINT: {
  472.       HDC hdc;
  473.       PAINTSTRUCT ps;
  474.       RECT rect;
  475.       hdc = BeginPaint(hwnd, &ps);
  476.       GetClientRect (hwnd, &rect);
  477.       hfont = (HFONT) GetWindowLong (hwnd, GWL_USERDATA);
  478.       SelectObject (hdc,hfont);
  479.       SetBkMode (hdc, TRANSPARENT);
  480.       SetTextAlign (hdc, TA_LEFT | TA_TOP | TA_UPDATECP);
  481.       GetTextMetrics (hdc, &tm);
  482.       MoveToEx (hdc, 0,0, NULL);
  483.       switch (gDisplaymode) {
  484.         case IDM_MODEHELLO: {
  485.           TCHAR szFace[LF_FACESIZE+2];
  486.           TCHAR szBuffer[LF_FACESIZE+100];
  487.           SIZE  ExtentSize;
  488.           SetViewportOrgEx (hdc, rect.right /2, rect.bottom/2, NULL);
  489.           TextOut (hdc, 0, 0, szHello, lstrlen (szHello));
  490.           GetTextFace (hdc, LF_FACESIZE+2, szFace);
  491.           GetTextExtentPoint (hdc, szHello, lstrlen (szHello), &ExtentSize);
  492.           wsprintf (szBuffer,
  493.                     TEXT("GetTextFace: "%s",  GetTextExtentPoint: (%d, %d)"),
  494.                     szFace, ExtentSize.cx, ExtentSize.cy);
  495.           SetWindowText (hwndFaceBanner, szBuffer);
  496.         } break;
  497.         case IDM_MODETMRANGE: {
  498.           USHORT start, end;
  499.           topLineShowing= GetScrollPos (hwnd, SB_VERT);
  500.           start = tm.tmFirstChar;
  501.           start += (topLineShowing * nCharPerLine);
  502.           end = tm.tmLastChar;
  503.           BlamGlyphs (hdc, &tm, start, end, &rect, FALSE);
  504.         } break;
  505.         case IDM_MODEALL: {
  506.           USHORT start, end;
  507.           iSeg= GetScrollPos (hwnd, SB_HORZ);
  508.           topLineShowing = GetScrollPos (hwnd, SB_VERT);
  509.           start = startCount[iSeg];
  510.           start += (topLineShowing * nCharPerLine);
  511.           end = endCount[iSeg];
  512.           BlamGlyphs (hdc, &tm, start, end, &rect, FALSE);
  513.         } break;
  514.       } /* end switch */
  515.       EndPaint (hwnd, &ps);
  516.     } return FALSE; /* end WM_PAINT */
  517.     /**********************************************************************
  518.     *  WMU_PRINT
  519.     *
  520.     * user message.  Get an HDC for the printer, send it formatted
  521.     *  output based on the mode of the display window.
  522.     **********************************************************************/
  523.     case WMU_PRINT: {
  524.       HDC hdc;
  525.       RECT rect;
  526.       POINT point;
  527.       int nchar;
  528.       int ScrollMin, ScrollMax;
  529.       UINT cbData;
  530.       DOCINFO di;
  531.       di.cbSize      = sizeof(DOCINFO);
  532.       di.lpszDocName = TEXT("ttfonts");
  533.       di.lpszOutput  = NULL;
  534.       SetCursor (LoadCursor (NULL, IDC_WAIT));
  535.       hdc = GetPrinterDC();
  536.       if (hdc == NULL) return 0;
  537.       StartDoc  (hdc, &di);
  538.       StartPage (hdc);
  539.       hfont = (HFONT) GetWindowLong (hwnd, GWL_USERDATA);
  540.       SelectObject (hdc,hfont);
  541.       rect.top = rect.left = 0;
  542.       rect.right = GetDeviceCaps (hdc, HORZRES);
  543.       rect.bottom = GetDeviceCaps (hdc, VERTRES);
  544.       SetBkMode (hdc, TRANSPARENT);
  545.       SetTextAlign (hdc, TA_LEFT | TA_TOP | TA_UPDATECP);
  546.       GetTextMetrics (hdc, &tm);
  547.       /* write a little banner at the top */
  548.       MoveToEx (hdc, 0,0, NULL);
  549.       TextOut (hdc, 0,0,TEXT ("ttfonts -- "), 11);
  550.       cbData = GetOutlineTextMetrics (hdc, 0, NULL);
  551.       if (cbData == 0) {
  552.         TextOut (hdc, 0,0, szFontDataErr,
  553.                 lstrlen(szFontDataErr));
  554.       } else {
  555.         LPOUTLINETEXTMETRIC lpoltm;
  556.         LPBYTE lptStr;
  557.         lpoltm = (LPOUTLINETEXTMETRIC)LocalAlloc (LPTR, cbData);
  558.         GetOutlineTextMetrics (hdc, cbData, lpoltm);
  559.         lptStr = (LPBYTE)lpoltm;
  560.         lptStr += (UINT) (PBYTE) lpoltm->otmpFamilyName;
  561.         TextOut (hdc, 0,0, (LPCTSTR) lptStr, lstrlen((LPCTSTR)lptStr));
  562.         LocalFree (LocalHandle (lpoltm));
  563.       }
  564.       /* Draw a thick line, and leave the cursor in the right place. */
  565.       GetCurrentPositionEx (hdc, &point);  /* fill point */
  566.       point.x = rect.right;
  567.       point.y += tm.tmHeight;
  568.       for (i = 0; i<5; i++) {
  569.         MoveToEx (hdc, point.x, point.y, NULL);
  570.         LineTo (hdc, 0, point.y);
  571.         point.y++;
  572.       }
  573.       switch (gDisplaymode) {
  574.         case IDM_MODEHELLO:
  575.           SetViewportOrgEx (hdc, rect.right /2, rect.bottom/2, NULL);
  576.           TextOut (hdc, 0, 0, szHello, lstrlen (szHello));
  577.         break;
  578.         case IDM_MODETMRANGE:
  579.           BlamGlyphs (hdc, &tm, tm.tmFirstChar, tm.tmLastChar, &rect, TRUE);
  580.         break;
  581.         case IDM_MODEALL:
  582.           /* the horz scroll bar has the number of segments stored as
  583.            *  the scroll bar range, query and use it.
  584.            */
  585.           GetScrollRange (hwnd, SB_HORZ, &ScrollMin, &ScrollMax);
  586.           for (i = 0; i<= ScrollMax; i++) {
  587.             MoveToEx (hdc,rect.right, point.y, NULL);
  588.             LineTo (hdc, rect.left, point.y);
  589.             SelectObject (hdc,GetStockObject (DEVICE_DEFAULT_FONT));
  590.             nchar = wsprintf (buffer, TEXT("[%04x, %04x]"), (int)startCount[i],
  591.                                                       (int)endCount[i]);
  592.             TextOut (hdc, 0,0,buffer, nchar);
  593.             SelectObject (hdc,hfont);
  594.             BlamGlyphs (hdc, &tm, startCount[i], endCount[i], &rect, TRUE);
  595.             GetCurrentPositionEx (hdc, &point);
  596.             point.x = 0;
  597.             point.y += (tm.tmHeight + tm.tmExternalLeading);
  598.             MoveToEx (hdc, point.x, point.y, NULL);
  599.             if ((point.y+tm.tmHeight+tm.tmExternalLeading) > rect.bottom) {
  600.               point.x = point.y = 0;
  601.               EndPage   (hdc);
  602.               StartPage (hdc);
  603.               MoveToEx (hdc, point.x, point.y, NULL);
  604.             }
  605.           }
  606.         break;  /* end IDM_MODEALL */
  607.       } /* end switch */
  608.       EndPage   (hdc);
  609.       EndDoc    (hdc);
  610.       DeleteDC (hdc);
  611.       SetCursor (LoadCursor (NULL, IDC_ARROW));
  612.     } return TRUE;
  613.   } /* end switch */
  614.   return (DefMDIChildProc(hwnd, message, wParam, lParam));
  615. }
  616. /**************************************************************************
  617. *
  618. *  function:  BlamGlyphs
  619. *
  620. *  input parameters:
  621. *   hdc with font selected into it.
  622. *   pointer to a text metric structure.
  623. *   start and end of code point range to print
  624. *   pointer to rectangle which serves as bounds.
  625. *
  626. *  Starting at the current point, write one glyph after the other, starting
  627. *   with the "Start" parameter, and ending with the "End" parameter.  If
  628. *   the next character will overrun on the right, start again on a new line.
  629. *  Special case Start = 0xfff which happens because the start/endCount
  630. *   arrays always end with this value.
  631. *
  632. *
  633.   // UNICODE NOTICE
  634.   //  This function is held as unicode because it needs to display
  635.   //  wide characters (i.e. need TextOutW).
  636. *
  637. *
  638. **************************************************************************/
  639. VOID BlamGlyphs (HDC hdc, PTEXTMETRIC ptm, USHORT Start, USHORT End, PRECT prect, BOOL printing)
  640. {
  641. USHORT i;
  642. POINT point;
  643. WCHAR outChar;
  644.   if (Start == 0xffff) return;
  645.   for (i = Start; i<=End; i++) {
  646.     /* special case the non-spacing diacritic marks. U+0300 -> U+036F
  647.      *  Write a space first, for them to 'modify.'
  648.      */
  649.     if ( (0x0300 <= i) && (i <= 0x036F) ) {
  650.       outChar = (WCHAR) 0x0020;
  651.       TextOutW (hdc, 0,0, &outChar, 1);
  652.     }
  653.     outChar = (WCHAR) i;
  654.     TextOutW (hdc, 0,0, &outChar, 1);
  655.     /* Watch for overflow in x */
  656.     GetCurrentPositionEx (hdc, &point);
  657.     if (point.x > (prect->right - ptm->tmAveCharWidth)) {
  658.       point.x = 0;
  659.       point.y += (ptm->tmHeight + ptm->tmExternalLeading);
  660.       MoveToEx (hdc, point.x, point.y, NULL);
  661.     }
  662.     /* Watch for overflow in y */
  663.     if (printing) {
  664.       if (point.y > (prect->bottom-(ptm->tmHeight+ptm->tmExternalLeading))) {
  665.         EndPage   (hdc);
  666.         StartPage (hdc);
  667.         point.x = point.y = 0;
  668.         MoveToEx (hdc, point.x, point.y, NULL);
  669.       }
  670.     } else {
  671.       if (point.y > prect->bottom) {
  672.         return;
  673.       }
  674.     }
  675.   } /* end for (i= Start; i<=End ... */
  676. }
  677. /**************************************************************************
  678. *
  679. * All of the code below is used for parsing "font data."  It will only
  680. *  make sense if you have a copy of the True Type font spec.  In short,
  681. *  we grab the 'cmap' table, look through it for a subtable, and then
  682. *  get two parallel arrays from the subtable.  Complications arise because
  683. *  the true type data is "BIG ENDIAN" and NT is being run "little endian."
  684. *  For this reason, once we locate the short or long, we call Swap* to
  685. *  change the byte ordering.
  686. *
  687. **************************************************************************/
  688. VOID SwapShort (PUSHORT);
  689. VOID SwapULong  (PULONG);
  690. typedef struct tagTABLE{
  691.     USHORT platformID;
  692.     USHORT encodingID;
  693.     ULONG  offset;
  694. } TABLE, *PTABLE;
  695. typedef struct tagSUBTABLE{
  696.     USHORT format;
  697.     USHORT length;
  698.     USHORT version;
  699.     USHORT segCountX2;
  700.     USHORT searchRange;
  701.     USHORT entrySelector;
  702.     USHORT rangeShift;
  703. } SUBTABLE, *PSUBTABLE;
  704. /* 'cmap' is passed in by value in a DWORD */
  705. #define CMAPHEX  0x70616d63
  706. #define NBYTES   256
  707. #define OFFSETERROR  0
  708. /**************************************************************************
  709. *
  710. *  function:  CountUCSegments()
  711. *
  712. *  input parameters:
  713. *   hdc - with the logical font set into it.
  714. *   prect - pointer to client rectangle.
  715. *
  716. *  Global variables:
  717. *   startCount
  718. *   endCount
  719. *
  720. *  returns:
  721. *   number of UC segments or
  722. *   SEGMENTERROR if there is some kind of error.
  723. *
  724. *  essential side effect:
  725. *   Fills in global startCount, endCount arrays.
  726. **************************************************************************/
  727. int CountUCSegments (HDC hdc)
  728. {
  729. DWORD       cbData;
  730. USHORT      aShort[2];
  731. DWORD       nBytes;
  732. USHORT      i, nTables;
  733. PTABLE      pTable;
  734. PSUBTABLE   pSubTable;
  735. ULONG       offset,offsetFormat4;
  736. USHORT      segCount;
  737. BYTE        buffer[NBYTES];
  738.     /* find number of "subtables", second long in cmap */
  739.     nBytes=GetFontData (hdc, CMAPHEX, 0, aShort, 4);
  740.     if (nBytes == GDI_ERROR) {
  741.       MessageBox (NULL, szFontDataErr, szMBERROR , MBERRORFLAGS);
  742.       return SEGMENTERROR;
  743.     }
  744.     if (nBytes == 0) {
  745.       MessageBox (NULL, szNoCMAPTable, szMBERROR , MBERRORFLAGS);
  746.       return SEGMENTERROR;
  747.     }
  748.     nTables = aShort[1];
  749.     SwapShort (&nTables);
  750.     cbData = nTables * sizeof(TABLE);
  751.     if (cbData >NBYTES) {
  752.       MessageBox (NULL, szCBDataTooBig, szMBERROR , MBERRORFLAGS);
  753.       return SEGMENTERROR;
  754.     }
  755.     /* get array of subtables information.  Check each one for 3,1*/
  756.     nBytes=GetFontData (hdc, CMAPHEX, 4, buffer, cbData);
  757.     pTable = (PTABLE)buffer;
  758.     offsetFormat4 = OFFSETERROR;
  759.     for (i = 0; i< nTables; i++) {
  760.         SwapShort (&(pTable->encodingID));
  761.         SwapShort (&(pTable->platformID));
  762.         if ((pTable->platformID == 3)&&(pTable->encodingID == 1)) {
  763.           offsetFormat4 = pTable->offset;
  764.           SwapULong (&offsetFormat4);
  765.           break;
  766.         }
  767.         pTable++;
  768.     }
  769.     /* verify that we got the correct offset to the FORMAT 4 subtable */
  770.     if (offsetFormat4 == OFFSETERROR){
  771.       MessageBox (NULL, szNoTable, szMBERROR , MBERRORFLAGS);
  772.       return SEGMENTERROR;
  773.     }
  774.     /* Get the beginning of the subtable, especially the segment count */
  775.     nBytes=GetFontData (hdc, CMAPHEX, offsetFormat4, buffer, sizeof(SUBTABLE));
  776.     pSubTable = (PSUBTABLE) buffer;
  777.     SwapShort (&(pSubTable->format));
  778.     SwapShort (&(pSubTable->segCountX2));
  779.     if (pSubTable->format != 4){
  780.       MessageBox (NULL, szFormatNot4, szMBERROR, MBERRORFLAGS);
  781.       return SEGMENTERROR;
  782.     }
  783.     segCount = pSubTable->segCountX2 / 2;
  784.     /* Now that we know how many segments that the font contains,
  785.      *  free up the old memory, and realloc. the two global arrays.
  786.      */
  787.     if (startCount != NULL) LocalFree (LocalHandle (startCount));
  788.     if (endCount != NULL) LocalFree (LocalHandle (endCount));
  789.     startCount = LocalAlloc (LPTR, segCount * sizeof(USHORT));
  790.     endCount = LocalAlloc (LPTR, segCount * sizeof(USHORT));
  791.     if ((startCount == NULL) || (endCount == NULL)) {
  792.       MessageBox (NULL, szAllocFailed, szMBERROR, MBERRORFLAGS);
  793.       return SEGMENTERROR;
  794.     }
  795.     /* read in the array of endCount values */
  796.     offset = offsetFormat4
  797.            + (7 * sizeof (USHORT));  /* skip constant # bytes in subtable */
  798.     cbData = segCount * sizeof (USHORT);
  799.     nBytes=GetFontData (hdc, CMAPHEX, offset, endCount, cbData );
  800.     for (i = 0; i<segCount; i++)
  801.         SwapShort (& (endCount[i]));
  802.     /* read in the array of startCount values */
  803.     offset = offsetFormat4
  804.            + (7 * sizeof (USHORT))   /* skip constant # bytes in subtable */
  805.            + (segCount * sizeof (USHORT)) /* skip endCount array */
  806.            + sizeof (USHORT);             /* skip reservedPad */
  807.     cbData = segCount * sizeof (USHORT);
  808.     nBytes=GetFontData (hdc, CMAPHEX, offset, startCount, cbData );
  809.     for (i = 0; i<segCount; i++)
  810.         SwapShort (& (startCount[i]));
  811.     return segCount;
  812. }
  813. VOID SwapShort (PUSHORT p)
  814. {
  815. SHORT temp;
  816.     temp =(SHORT)( HIBYTE (*p) + (LOBYTE(*p) << 8));
  817.     *p = temp;
  818. }
  819. VOID SwapULong (PULONG p)
  820. {
  821. ULONG temp;
  822.     temp = (LONG) ((BYTE) *p);
  823.     temp <<= 8;
  824.     *p >>=8;
  825.     temp += (LONG) ((BYTE) *p);
  826.     temp <<= 8;
  827.     *p >>=8;
  828.     temp += (LONG) ((BYTE) *p);
  829.     temp <<= 8;
  830.     *p >>=8;
  831.     temp += (LONG) ((BYTE) *p);
  832.     *p = temp;
  833. }