|
|
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 to support the main MDI child windows.
14: *
15: * This module contains Window Procedure, openDisplay() and closeDisplay()
16: * routines. Call openDisplay() one time per process before creating the
17: * first window, and call closeDisplay() one time at process termination.
18: *
19: * windows are created in main frame window procedure.
20: *
21: * design: We have one window procedure here for potentially multiple
22: * MDI child windows. The nCharPerLine, SqrHeight, and SqrWidth are
23: * stored on a per window basis. Also, the window class is registered
24: * with the style CS_OWNDC. For this reason, it is possible to select
25: * a logical font into the HDC, and it will be there each time you get
26: * the DC new for the window. In this way we have a log font for each
27: * window without actually doing any work in this module.
28: *
29: * Some of the data is global, and works for all of the windows. The
30: * startcount & endcount arrays are a good example. These are computed
31: * once when the font is created, but the values remain the same for each
32: * window. Thus we have the following assumption:
33: *
34: * 1. No fonts will be installed or removed while program is running.
35: * (CountUCSegments values remain valid for run time duration).
36: *
37: *
38: * There are WM_USER+ messages to set values for this window, and to
39: * notify it of global changes. Looking at the create time, user message
40: * stream is helpful. On the WM_CREATE message, we send ourselves a
41: * WMU_NEWFONT message to create a logical font and count the number of
42: * character ranges (segments). Before returning from this message, we
43: * send ourselves a WMU_NEWRANGE message to set the title, and the
44: * horizontal scroll bar correctly.
45: *
46: *
47: \**************************************************************************/
48: #define UNICODE
49:
50: #include <windows.h>
51: #include "uniput.h"
52: #include "display.h"
53:
54:
55: /* global variables store the start and end codepoints for UC ranges. */
56: #define MAXSEGMENTS 100
57: USHORT *endCount= NULL;
58: USHORT *startCount= NULL;
59:
60: int CountUCSegments (HDC);
61: /* error return value from CountUCSegments */
62: #define SEGMENTERROR -1
63:
64:
65: /* conversion between (x,y) pairs and rectangle index */
66: int transXYtoIndex (int, int, int, int, int);
67: int transIndextoRect (int, PRECT, int, int, int);
68:
69:
70: /* window extra bytes for use to store window specific data (see register class) */
71: #define GWLU_NCHAR 0
72: #define GWLU_SQRHEIGHT 4
73: #define GWLU_SQRWIDTH 8
74:
75:
76:
77:
78:
79: /* Global logfont. Used for CreateFontIndirect().
80: * also regerenced in the uniput.c file.
81: */
82: LOGFONT logfont = {
83: UCFONTHEIGHT ,
84: UCFONTWIDTH ,
85: 0 ,
86: 0 ,
87: 400 ,
88: 0 ,
89: 0 ,
90: 0 ,
91: UNICODE_CHARSET ,
92: 0 ,
93: 0 ,
94: 2 ,
95: 2 ,
96: TEXT("Lucida Sans Unicode")};
97:
98:
99: /* Global, class specific data.
100: * ought to allocate once per class, and free once at app exit time.
101: */
102: HDC hdcMemXOR;
103: HBITMAP hbmMemXOR;
104: PVOID pbitsXOR, pbitsAND;
105:
106: int FontWidth, FontHeight;
107: int nSegments;
108:
109: /**************************************************************************\
110: *
111: * function: openDisplay()
112: *
113: * Global variables:
114: * HDC hdcMemXOR;
115: * HBITMAP hbmMemXOR;
116: * PVOID pbitsXOR, pbitsAND;
117: * int FontWidth, FontHeight;
118: * int nSegments;
119: *
120: * returns: TRUE - if success, FALSE - if fail.
121: *
122: * essential side effect:
123: * Registers window class, and initial global variables.
124: \**************************************************************************/
125: int openDisplay(VOID )
126: {
127: WNDCLASS wc;
128: static int cxCursor, cyCursor;
129: HFONT hfont;
130:
131: /* Register the window class*/
132: wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
133: wc.lpfnWndProc = (WNDPROC)DisplayWndProc;
134: wc.cbClsExtra = 0;
135: wc.cbWndExtra = 12;
136: wc.hInstance = hInst;
137: wc.hIcon = LoadIcon(hInst, TEXT("uniputIcon"));
138: wc.hCursor = LoadCursor(NULL, IDC_ARROW);
139: wc.hbrBackground = GetStockObject (WHITE_BRUSH);
140: wc.lpszMenuName = NULL;
141: wc.lpszClassName = DISPLAYCLASS;
142:
143: if (!RegisterClass(&wc)) return (FALSE);
144:
145: cxCursor = GetSystemMetrics (SM_CXCURSOR);
146: cyCursor = GetSystemMetrics (SM_CYCURSOR);
147:
148: /* get pointer to 0-init memory */
149: pbitsAND = (PVOID) LocalAlloc (LPTR, cxCursor*cyCursor/8);
150:
151: /* Create a memory DC to draw into for creating cursors. */
152: hdcMemXOR = CreateCompatibleDC (NULL);
153: hbmMemXOR = CreateBitmap (cxCursor,cyCursor,1,4,NULL);
154: SelectObject (hdcMemXOR, hbmMemXOR);
155:
156: /* set text modes for the memory HDC */
157: SetBkMode (hdcMemXOR, TRANSPARENT);
158: SetTextAlign (hdcMemXOR, TA_CENTER | TA_TOP);
159:
160: /* set a unicode font into the memory DC */
161: logfont.lfHeight = cyCursor *2/3; // HACK.. scale down Y
162: logfont.lfWidth = cxCursor *2/3;
163: hfont = CreateFontIndirect (&logfont);
164: SelectObject (hdcMemXOR, hfont);
165:
166: /* get pointer to be used later as pointer to bitmap bits */
167: pbitsXOR = (PVOID) LocalAlloc (LPTR, cxCursor*cyCursor/2);
168:
169: /* Assume that we got a unicode font.
170: * Count the number of segments, and fill in the proper global
171: * variables specifying the code point ranges covered.
172: */
173: nSegments = CountUCSegments (hdcMemXOR); /* slow computation */
174:
175:
176: /* verify that we have SOME ranges to work with */
177: if (nSegments == SEGMENTERROR) return FALSE;
178:
179: /* warn the user if we can't find the right font */
180: if (nSegments < 30)
181: MessageBox (NULL,
182: TEXT("Working with limited codepoint coverage. \n Install uclucida.ttf"),
183: TEXT("Warning: Lucida Sans Unicode font not found."), MB_OK);
184:
185:
186:
187: FontWidth = UCFONTWIDTH;
188: FontHeight = UCFONTHEIGHT;
189:
190: return TRUE;
191: }
192:
193: /**************************************************************************\
194: *
195: * function: closeDisplay()
196: *
197: * Global variables:
198: * HDC hdcMemXOR;
199: * HBITMAP hbmMemXOR;
200: * PVOID pbitsXOR, pbitsAND;
201: *
202: * essential side effect:
203: * Frees global variables.
204: \**************************************************************************/
205: int closeDisplay(VOID)
206: {
207: HFONT hfont;
208:
209: hfont = SelectObject (hdcMemXOR, GetStockObject(SYSTEM_FONT));
210: DeleteObject (hfont);
211: DeleteDC (hdcMemXOR);
212: DeleteObject (hbmMemXOR);
213:
214: LocalFree (LocalHandle (pbitsXOR));
215: LocalFree (LocalHandle (pbitsAND));
216: return TRUE;
217: }
218:
219:
220: /**************************************************************************\
221: *
222: * function: DisplayWndProc()
223: *
224: * input parameters: normal window procedure parameters.
225: *
226: \**************************************************************************/
227: LRESULT CALLBACK DisplayWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
228: {
229: static HFONT hfont, hfontOld;
230:
231: static HDC hdc;
232: static RECT rect;
233: static int iSeg;
234: static TCHAR buffer[100];
235:
236: /* rDown and index used as the user points to a square. */
237: static RECT rDown;
238: static int index;
239:
240: static WCHAR DragDropChar;
241: static HICON hIcon;
242:
243:
244:
245: switch (message) {
246:
247: /**********************************************************************\
248: * WM_CREATE
249: *
250: * Set up the LOGFONT in the HDC for this window.
251: \**********************************************************************/
252: case WM_CREATE:
253: SendMessage (hwnd, WMU_SETNCHAR, 16, 0);
254: SendMessage (hwnd, WMU_NEWFONT, FontWidth, FontHeight);
255: break;
256:
257:
258: /**********************************************************************\
259: * WM_DESTROY
260: *
261: * Get rid of the logical font we create for each display window.
262: * relying here on CS_ONWDC
263: \**********************************************************************/
264: case WM_DESTROY:
265: hdc = GetDC (hwnd);
266: hfont = SelectObject (hdc, GetStockObject(SYSTEM_FONT));
267: DeleteObject (hfont);
268: ReleaseDC (hwnd, hdc);
269:
270: if (startCount != NULL) LocalFree (LocalHandle (startCount));
271: if (endCount != NULL) LocalFree (LocalHandle (endCount));
272:
273: break;
274:
275:
276:
277:
278:
279: /**********************************************************************\
280: * WMU_SETNCHAR
281: *
282: * wParam - nCharPerLine
283: *
284: \**********************************************************************/
285: case WMU_SETNCHAR:
286: SetWindowLong (hwnd, GWLU_NCHAR, (int) wParam);
287: InvalidateRect (hwnd, NULL, TRUE);
288: break;
289:
290: /**********************************************************************\
291: * WMU_NEWFONT
292: *
293: * wParam - Width
294: * lParam - Height
295: *
296: * Create font, select it into the HDC, and reset ranges.
297: \**********************************************************************/
298: case WMU_NEWFONT: {
299:
300: hdc = GetDC(hwnd);
301:
302: FontWidth = (int) wParam;
303: FontHeight = (int) lParam;
304: logfont.lfHeight = FontHeight;
305: logfont.lfWidth = FontWidth;
306:
307: hfont = CreateFontIndirect (&logfont);
308: hfontOld = SelectObject (hdc, hfont);
309: DeleteObject (hfontOld);
310:
311: ReleaseDC (hwnd, hdc);
312:
313:
314: SetScrollRange (hwnd, SB_HORZ, 0, (nSegments-1), TRUE);
315: SetScrollPos (hwnd, SB_HORZ, 0, TRUE);
316:
317: SendMessage (hwnd, WMU_NEWRANGE, 0,0);
318:
319: } return TRUE;
320:
321:
322: /**********************************************************************\
323: * WMU_NEWRANGE
324: *
325: *
326: * Range changes, or font size changes, or title status changes.
327: \**********************************************************************/
328: case WMU_NEWRANGE: {
329: int sqrHeight, sqrWidth;
330: TEXTMETRIC tm;
331: int i;
332:
333: hdc = GetDC(hwnd);
334: GetTextMetrics (hdc, &tm);
335: ReleaseDC (hwnd, hdc);
336:
337: /* index into the start, end arrays stored in scroll bar */
338: iSeg = GetScrollPos (hwnd, SB_HORZ);
339:
340: /* Set the window title text to show display range. */
341: wsprintf (buffer, TEXT("[%04x, %04x]"),
342: (int)startCount[iSeg],
343: (int)endCount[iSeg]);
344:
345: /* if we are supposed to look up the character range name,
346: * then step through the ranges stored in the RangeName
347: * table. Find the correct one, and reset the buffer string.
348: */
349: if (gShowNames) {
350: for (i = 0; i< NRANGE; i++) {
351: if ((RangeName[i].start <= startCount[iSeg]) &&
352: ( startCount[iSeg] <= RangeName[i].end))
353:
354: wsprintf (buffer, TEXT("%s [%04x, %04x]"),
355: RangeName[i].String,
356: (int)startCount[iSeg],
357: (int)endCount[iSeg]);
358:
359: }
360: }
361: SetWindowText (hwnd, buffer);
362:
363: sqrHeight = tm.tmHeight + tm.tmExternalLeading;
364: sqrWidth = tm.tmMaxCharWidth;
365:
366: SetWindowLong (hwnd, GWLU_SQRHEIGHT,sqrHeight);
367: SetWindowLong (hwnd, GWLU_SQRWIDTH, sqrWidth );
368:
369: } return TRUE;
370:
371:
372:
373:
374:
375:
376:
377:
378:
379: /**********************************************************************\
380: * WM_LBUTTONDOWN
381: *
382: * Static, shared variables set in WM_LBUTTONDOWN:
383: * rDown, hIcon, DragDropChar
384: *
385: \**********************************************************************/
386: case WM_LBUTTONDOWN: {
387: int x,y;
388: int nCharPerLine;
389: int sqrHeight, sqrWidth;
390: nCharPerLine = GetWindowLong (hwnd, GWLU_NCHAR);
391: sqrHeight = GetWindowLong (hwnd, GWLU_SQRHEIGHT);
392: sqrWidth = GetWindowLong (hwnd, GWLU_SQRWIDTH );
393:
394:
395:
396: x = (int)LOWORD (lParam);
397: y = (int)HIWORD (lParam);
398:
399: index = transXYtoIndex (x,y, sqrWidth, sqrHeight, nCharPerLine);
400:
401: /* verify that the index is within the shown segment range */
402: iSeg= GetScrollPos (hwnd, SB_HORZ);
403: if (index > (endCount[iSeg]- startCount[iSeg])) return 0;
404:
405: DragDropChar = index + startCount[iSeg];
406:
407: transIndextoRect (index, &rDown, sqrWidth, sqrHeight, nCharPerLine);
408:
409: hdc = GetDC (hwnd);
410: InvertRect (hdc, &rDown);
411: ReleaseDC (hwnd, hdc);
412:
413:
414: /* Create a cursor which represents the character.
415: * Global variables used:
416: * HDC hdcMemXOR;
417: * HBITMAP hbmMemXOR;
418: * PVOID pbitsXOR, pbitsAND;
419: */
420: {
421: int cxCursor, cyCursor;
422: RECT rect;
423:
424: cxCursor = GetSystemMetrics (SM_CXCURSOR);
425: cyCursor = GetSystemMetrics (SM_CYCURSOR);
426:
427: rect.left = rect.top = 0;
428: rect.right = cxCursor; rect.bottom = cyCursor;
429:
430:
431: FrameRect (hdcMemXOR, &rect, GetStockObject (BLACK_BRUSH));
432: InflateRect (&rect, -1, -1);
433: FillRect (hdcMemXOR, &rect, GetStockObject (LTGRAY_BRUSH));
434: FrameRect (hdcMemXOR, &rect, GetStockObject (GRAY_BRUSH));
435: InflateRect (&rect, -1, -1);
436: SelectObject (hdcMemXOR, GetStockObject (WHITE_PEN));
437: MoveToEx (hdcMemXOR, rect.right, rect.top, NULL);
438: LineTo (hdcMemXOR,rect.left, rect.top);
439: LineTo (hdcMemXOR,rect.left, rect.bottom);
440:
441: ExtTextOut(hdcMemXOR, cxCursor/2,0, ETO_CLIPPED, &rect,
442: (LPCWSTR)&DragDropChar, 1, NULL);
443:
444: GetBitmapBits (hbmMemXOR, cxCursor*cyCursor/2, pbitsXOR);
445:
446: hIcon = CreateIcon( GetModuleHandle(NULL),
447: cxCursor,cyCursor, 1,4,
448: pbitsAND,
449: pbitsXOR);
450:
451: SetCursor ((HCURSOR)hIcon);
452: }
453:
454:
455:
456: GdiFlush ();
457: SetCapture (hwnd);
458: } break;
459:
460: /**********************************************************************\
461: * WM_LBUTTONUP
462: *
463: * Static, shared variables set in WM_LBUTTONDOWN:
464: * rDown, hIcon, DragDropChar
465: *
466: \**********************************************************************/
467: case WM_LBUTTONUP: {
468: POINT p;
469: HWND hwndTarget, hwndTitle;
470: #define NUMCHARS 255
471: TCHAR buffer[NUMCHARS];
472:
473:
474: if (GetCapture() == hwnd) {
475:
476: p.x = (int)(short)LOWORD (lParam);
477: p.y = (int)(short)HIWORD (lParam);
478:
479: ClientToScreen (hwnd, &p);
480: hwndTarget = WindowFromPoint (p);
481:
482: if ((GetWindowThreadProcessId (hwnd, NULL)) !=
483: (GetWindowThreadProcessId (hwndTarget, NULL))) {
484:
485: /* hack. unipad has a client window which gets the chars,
486: * but we want to display the frame windows text (title bar),
487: * so try to get the parent of the target for Title purposes.
488: */
489: hwndTitle = (GetParent(hwndTarget)) ? GetParent(hwndTarget) : hwndTarget;
490: GetWindowText (hwndTitle, buffer, NUMCHARS);
491:
492: SendMessage (hwndTarget, WM_CHAR, (WPARAM) DragDropChar, 0);
493: SendMessage (hwndStatus, WMU_CHARACTER,
494: (WPARAM) DragDropChar, (LPARAM)hwndTarget);
495: SendMessage (hwndStatus, WMU_SETTARGETNAME,
496: (WPARAM) IsWindowUnicode (hwndTarget), (LPARAM)buffer);
497: } /* end different process */
498:
499: Beep (40,40);
500:
501: hdc = GetDC (hwnd);
502: InvertRect (hdc, &rDown);
503: ReleaseDC (hwnd, hdc);
504: GdiFlush ();
505: ReleaseCapture ();
506: SetCursor ((HCURSOR)LoadCursor (NULL, IDC_ARROW));
507: DestroyIcon (hIcon);
508: }
509: } break;
510:
511:
512:
513: /**********************************************************************\
514: * WM_HSCROLL
515: *
516: * Step through the character ranges.
517: * In every case, inform the window the range has changed,
518: * and invalidate it to force a repaint.
519: \**********************************************************************/
520: case WM_HSCROLL:
521:
522: switch (LOWORD(wParam)){
523: int OldPos, NewPos;
524:
525: case SB_PAGEDOWN:
526: case SB_LINEDOWN:
527: OldPos = GetScrollPos (hwnd, SB_HORZ);
528: SetScrollPos (hwnd, SB_HORZ, (OldPos+1), TRUE);
529: SendMessage (hwnd,WMU_NEWRANGE, 0,0);
530: InvalidateRect (hwnd, NULL, TRUE);
531: break;
532:
533: case SB_PAGEUP:
534: case SB_LINEUP:
535: OldPos = GetScrollPos (hwnd, SB_HORZ);
536: SetScrollPos (hwnd, SB_HORZ, (OldPos-1), TRUE);
537: SendMessage (hwnd,WMU_NEWRANGE, 0,0);
538: InvalidateRect (hwnd, NULL, TRUE);
539: break;
540:
541: case SB_THUMBPOSITION:
542: OldPos = GetScrollPos (hwnd, SB_HORZ);
543: NewPos = HIWORD (wParam);
544: SetScrollPos (hwnd, SB_HORZ, NewPos, TRUE);
545: SendMessage (hwnd,WMU_NEWRANGE, 0,0);
546: InvalidateRect (hwnd, NULL, TRUE);
547: break;
548:
549: }
550:
551: break;
552:
553:
554:
555:
556:
557:
558:
559: /**********************************************************************\
560: * WM_SIZE
561: *
562: \**********************************************************************/
563: case WM_SIZE:
564: /* make sure that scroll metrics are ok */
565: SendMessage (hwnd, WMU_NEWRANGE, 0,0);
566:
567: break; /* fall through to MDIChildProc */
568:
569:
570: /**********************************************************************\
571: * WM_PAINT
572: *
573: \**********************************************************************/
574: case WM_PAINT: {
575: HDC hdc;
576: PAINTSTRUCT ps;
577: RECT rect;
578: POINT point;
579: int i;
580: USHORT start, end;
581: WCHAR outChar;
582: USHORT codepoint;
583: int nCharPerLine;
584: int sqrHeight, sqrWidth;
585: nCharPerLine = GetWindowLong (hwnd, GWLU_NCHAR);
586: sqrHeight = GetWindowLong (hwnd, GWLU_SQRHEIGHT);
587: sqrWidth = GetWindowLong (hwnd, GWLU_SQRWIDTH );
588:
589:
590: hdc = BeginPaint(hwnd, &ps);
591: SetBkMode (hdc, TRANSPARENT);
592:
593: iSeg= GetScrollPos (hwnd, SB_HORZ);
594: start = startCount[iSeg];
595: end = endCount[iSeg];
596:
597: /* ensure that we are in a valid range... some fonts have problems */
598: if (start != 0xffff)
599:
600: for (codepoint = start, i=0; codepoint<=end; codepoint++,i++) {
601:
602: /* paint box and frame it */
603: transIndextoRect (i, &rect, sqrWidth, sqrHeight, nCharPerLine);
604: InflateRect (&rect, -1, -1);
605: FillRect (hdc, &rect, GetStockObject (LTGRAY_BRUSH));
606: InflateRect (&rect, 1, 1);
607: FrameRect (hdc, &rect, GetStockObject (GRAY_BRUSH));
608: InflateRect (&rect, -1, -1);
609: SelectObject (hdc, GetStockObject (WHITE_PEN));
610: MoveToEx (hdc, rect.right, rect.top, NULL);
611: LineTo (hdc,rect.left, rect.top);
612: LineTo (hdc,rect.left, rect.bottom);
613:
614:
615:
616: /* set point that we will draw glyph at */
617: point.x = (rect.right + rect.left)/2;
618: point.y = rect.top;
619: SetTextAlign (hdc, TA_CENTER | TA_TOP);
620: SetTextColor (hdc, PALETTEINDEX (0));
621:
622:
623: /* special case the non-spacing diacritic marks. U+0300 -> U+036F
624: * Write a space first, for them to 'modify.'
625: */
626: if ( (0x0300 <= codepoint) && (codepoint <= 0x036F) ) {
627: outChar = (WCHAR) 0x0020;
628: TextOutW (hdc, 0,0, &outChar, 1);
629: }
630:
631: outChar = (WCHAR) codepoint;
632: ExtTextOut(hdc, point.x, point.y, ETO_CLIPPED, &rect, (LPCWSTR)&outChar, 1, NULL);
633:
634:
635:
636: /* fill in unicode code point in hex */
637: if (gShowhex) {
638: int nchar;
639: HANDLE hfonttemp;
640:
641: nchar = wsprintf (buffer, TEXT("%04x"), (int) codepoint);
642: hfonttemp = SelectObject (hdc,GetStockObject (SYSTEM_FIXED_FONT));
643:
644: point.y = rect.bottom;
645: SetTextAlign (hdc, TA_CENTER | TA_BOTTOM);
646: SetTextColor (hdc, PALETTEINDEX (5));
647:
648: TextOut( hdc, point.x, point.y,
649: buffer, nchar);
650: SelectObject (hdc,hfonttemp);
651: }
652:
653:
654: } /* end for */
655:
656: EndPaint (hwnd, &ps);
657: } return FALSE; /* end WM_PAINT */
658:
659:
660:
661:
662: } /* end switch */
663:
664: return (DefMDIChildProc(hwnd, message, wParam, lParam));
665: }
666:
667:
668:
669:
670: /**************************************************************************\
671: *
672: * Need a mapping between the (x,y) pair, and the index of the square on
673: * the window. Two routines provide this... one for each direction.
674: *
675: \**************************************************************************/
676:
677: /**********************************************************************\
678: * transXYtoIndex
679: *
680: * Given x & y values, return the index.
681: *
682: \**********************************************************************/
683: int transXYtoIndex (int x, int y,
684: int sqrWidth, int sqrHeight, int nCharPerLine)
685: {
686: x /= sqrWidth;
687: if (x < 0) x = 0;
688: if (x >= nCharPerLine) x = nCharPerLine-1;
689:
690: y /= sqrHeight;
691: if (y < 0) y = 0;
692:
693: return ( (y * nCharPerLine) + x);
694: }
695:
696:
697: /**********************************************************************\
698: * transIndextoRect
699: *
700: * Given an index, i.e. the number of one of the squares on the display
701: * window, fill in the rectangle structure.
702: *
703: \**********************************************************************/
704: int transIndextoRect (int index, PRECT pr,
705: int sqrWidth, int sqrHeight, int nCharPerLine)
706: {
707: int x,y;
708:
709: x = index % nCharPerLine;
710: y = index / nCharPerLine;
711:
712: pr->left = x*sqrWidth;
713: pr->top = y*sqrHeight;
714: pr->right = pr->left +sqrWidth;
715: pr->bottom = pr->top +sqrHeight;
716:
717: return TRUE;
718: }
719:
720:
721:
722:
723:
724:
725: /**************************************************************************\
726: *
727: * All of the code below is used for parsing 'font data.' It will only
728: * make sense if you have a copy of the True Type font spec. In short,
729: * we grab the 'cmap' table, look through it for a subtable, and then
730: * get two parallel arrays from the subtable. Complications arise because
731: * the true type data is 'BIG ENDIAN' and NT is being run 'little endian.'
732: * For this reason, once we locate the short or long, we call Swap* to
733: * change the byte ordering.
734: *
735: \**************************************************************************/
736:
737:
738: VOID SwapShort (PUSHORT);
739: VOID SwapULong (PULONG);
740:
741:
742:
743: typedef struct tagTABLE{
744: USHORT platformID;
745: USHORT encodingID;
746: ULONG offset;
747: } TABLE, *PTABLE;
748:
749: typedef struct tagSUBTABLE{
750: USHORT format;
751: USHORT length;
752: USHORT version;
753: USHORT segCountX2;
754: USHORT searchRange;
755: USHORT entrySelector;
756: USHORT rangeShift;
757: } SUBTABLE, *PSUBTABLE;
758:
759:
760: /* 'cmap' is passed in by value in a DWORD */
761: #define CMAPHEX 0x70616d63
762: #define NBYTES 256
763: #define OFFSETERROR 0
764:
765:
766:
767: /**************************************************************************\
768: *
769: * function: CountUCSegments()
770: *
771: * input parameters:
772: * hdc - with the logical font set into it.
773: * prect - pointer to client rectangle.
774: *
775: * Global variables:
776: * startCount
777: * endCount
778: *
779: * returns:
780: * number of UC segments or
781: * SEGMENTERROR if there is some kind of error.
782: *
783: * essential side effect:
784: * Fills in global startCount, endCount arrays.
785: \**************************************************************************/
786: int CountUCSegments (HDC hdc)
787: {
788: DWORD cbData;
789: USHORT aShort[2];
790: DWORD nBytes;
791: USHORT i, nTables;
792: PTABLE pTable;
793: PSUBTABLE pSubTable;
794: ULONG offset,offsetFormat4;
795: USHORT segCount;
796: BYTE buffer[NBYTES];
797:
798:
799:
800:
801: /* find number of "subtables", second long in cmap */
802: nBytes=GetFontData (hdc, CMAPHEX, 0, aShort, 4);
803: if (nBytes == GDI_ERROR) {
804: MessageBox (NULL, MBGETFONTDATAERR,MBERROR , MBERRORFLAGS);
805: return SEGMENTERROR;
806: }
807: if (nBytes == 0) {
808: MessageBox (NULL, TEXT("No 'cmap' table."),MBERROR , MBERRORFLAGS);
809: return SEGMENTERROR;
810: }
811: nTables = aShort[1];
812: SwapShort (&nTables);
813:
814:
815: cbData = nTables * sizeof(TABLE);
816: if (cbData >NBYTES) {
817: MessageBox (NULL, TEXT("cbData >NBYTES"),MBERROR , MBERRORFLAGS);
818: return SEGMENTERROR;
819: }
820:
821: /* get array of subtables information. Check each one for 3,1*/
822: nBytes=GetFontData (hdc, CMAPHEX, 4, buffer, cbData);
823: pTable = (PTABLE)buffer;
824: offsetFormat4 = OFFSETERROR;
825: for (i = 0; i< nTables; i++) {
826:
827: SwapShort (&(pTable->encodingID));
828: SwapShort (&(pTable->platformID));
829:
830: if ((pTable->platformID == 3)&&(pTable->encodingID == 1)) {
831: offsetFormat4 = pTable->offset;
832: SwapULong (&offsetFormat4);
833: break;
834: }
835: pTable++;
836: }
837:
838: /* verify that we got the correct offset to the FORMAT 4 subtable */
839: if (offsetFormat4 == OFFSETERROR){
840: MessageBox (NULL, TEXT("Can not find 3,1 subtable"),MBERROR , MBERRORFLAGS);
841: return SEGMENTERROR;
842: }
843:
844: /* Get the beginning of the subtable, especially the segment count */
845: nBytes=GetFontData (hdc, CMAPHEX, offsetFormat4, buffer, sizeof(SUBTABLE));
846: pSubTable = (PSUBTABLE) buffer;
847: SwapShort (&(pSubTable->format));
848: SwapShort (&(pSubTable->segCountX2));
849:
850: if (pSubTable->format != 4){
851: MessageBox (NULL, TEXT("format !=4"), MBERROR, MBERRORFLAGS);
852: return SEGMENTERROR;
853: }
854:
855: segCount = pSubTable->segCountX2 / 2;
856:
857: /* Now that we know how many segments that the font contains,
858: * free up the old memory, and realloc. the two global arrays.
859: */
860: if (startCount != NULL) LocalFree (LocalHandle (startCount));
861: if (endCount != NULL) LocalFree (LocalHandle (endCount));
862: startCount = LocalAlloc (LPTR, segCount * sizeof(USHORT));
863: endCount = LocalAlloc (LPTR, segCount * sizeof(USHORT));
864:
865: if ((startCount == NULL) || (endCount == NULL)) {
866: MessageBox (NULL, TEXT("LocalAlloc failed"), MBERROR, MBERRORFLAGS);
867: return SEGMENTERROR;
868: }
869:
870: /* read in the array of endCount values */
871: offset = offsetFormat4
872: + (7 * sizeof (USHORT)); /* skip constant # bytes in subtable */
873: cbData = segCount * sizeof (USHORT);
874: nBytes=GetFontData (hdc, CMAPHEX, offset, endCount, cbData );
875: for (i = 0; i<segCount; i++)
876: SwapShort (& (endCount[i]));
877:
878: /* read in the array of startCount values */
879: offset = offsetFormat4
880: + (7 * sizeof (USHORT)) /* skip constant # bytes in subtable */
881: + (segCount * sizeof (USHORT)) /* skip endCount array */
882: + sizeof (USHORT); /* skip reservedPad */
883: cbData = segCount * sizeof (USHORT);
884: nBytes=GetFontData (hdc, CMAPHEX, offset, startCount, cbData );
885: for (i = 0; i<segCount; i++)
886: SwapShort (& (startCount[i]));
887:
888:
889: return segCount;
890: }
891:
892:
893:
894:
895:
896:
897:
898:
899:
900:
901: VOID SwapShort (PUSHORT p)
902: {
903: SHORT temp;
904:
905: temp =(SHORT)( HIBYTE (*p) + (LOBYTE(*p) << 8));
906: *p = temp;
907: }
908:
909:
910:
911: VOID SwapULong (PULONG p)
912: {
913: ULONG temp;
914:
915: temp = (LONG) ((BYTE) *p);
916: temp <<= 8;
917: *p >>=8;
918:
919: temp += (LONG) ((BYTE) *p);
920: temp <<= 8;
921: *p >>=8;
922:
923: temp += (LONG) ((BYTE) *p);
924: temp <<= 8;
925: *p >>=8;
926:
927: temp += (LONG) ((BYTE) *p);
928: *p = temp;
929: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.