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