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