home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / quot210s.zip / src / typeset.c < prev   
C/C++ Source or Header  |  1998-12-10  |  11KB  |  389 lines

  1. /*
  2.  * typeset.c
  3.  *
  4.  * HTML typesetting functions.
  5.  *
  6.  *      Created: 26th November, 1997 (split from paint.c)
  7.  * Version 2.00: 21st December, 1997
  8.  * Version 2.10: 8th September, 1998
  9.  *
  10.  * (C) 1997-1998 Nicholas Paul Sheppard
  11.  *
  12.  * This file is distributed under the GNU General Public License. See the
  13.  * file copying.txt for details.
  14.  */
  15.  
  16. #ifndef GENERIC
  17. # define INCL_GPI
  18. # include <os2.h>
  19. #endif
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include "html.h"
  24. #include "typeset.h"
  25.  
  26. /* internal function prototypes */
  27. #ifndef GENERIC
  28. void TypesetGpiString(HPS, char *, POINTL *, int);
  29. void TypesetGpiWord(HPS, char *, int *, int *, int, POINTL *);
  30. #endif
  31.  
  32. #ifndef GENERIC
  33. HMF TypesetMetafile(HAB hab, HWND hwnd, char **papszString, RECTL *prectlBoundary, FATTRS *pfattrs)
  34. /*
  35.  * Typeset an HTML string into a metafile, formatted for the given window.
  36.  *
  37.  * HAB hab            - handle to our anchor block
  38.  * HWND hwnd            - the handle of the window to typeset for
  39.  * char **papszString        - sequence of strings to be typeset, NULL to terminate
  40.  * RECTL *prectlBoundary    - structure to receive boundary information
  41.  * FATTRS *pfattrs        - font attribute structure for the font to typeset in
  42.  *
  43.  * Returns            - handle to the new metafile
  44.  */
  45. {
  46.     DEVOPENSTRUC    dos;
  47.     HDC        hdc;
  48.     HPS        hps;
  49.     SIZEL        sizel;
  50.     FONTMETRICS    fm;
  51.     FATTRS        fattrs;
  52.     RECTL        rectl;
  53.     POINTL        ptPos;
  54.     int        i;
  55.  
  56.     /* open metafile */
  57.     dos.pszLogAddress = NULL;
  58.     dos.pszDriverName = "DISPLAY";
  59.     hdc = DevOpenDC(hab, OD_METAFILE, "*", 2, (PDEVOPENDATA)&dos, NULLHANDLE);
  60.     sizel.cx = sizel.cy = 0;
  61.     hps = GpiCreatePS(hab, hdc, &sizel, PU_PELS | GPIA_ASSOC);
  62.  
  63.     /* create our fonts */
  64.     memcpy(&fattrs, pfattrs, sizeof(FATTRS));
  65.     GpiCreateLogFont(hps, NULL, IDF_NORMAL, &fattrs);
  66.     fattrs.fsSelection = FATTR_SEL_ITALIC;
  67.     GpiCreateLogFont(hps, NULL, IDF_ITALIC, &fattrs);
  68.     fattrs.fsSelection = FATTR_SEL_BOLD;
  69.     GpiCreateLogFont(hps, NULL, IDF_BOLD, &fattrs);
  70.     fattrs.fsSelection = FATTR_SEL_BOLD | FATTR_SEL_ITALIC;
  71.     GpiCreateLogFont(hps, NULL, IDF_BOLDITALIC, &fattrs);
  72.  
  73.     /* typeset the strings */
  74.     GpiErase(hps);
  75.     WinQueryWindowRect(hwnd, &rectl);
  76.     GpiSetCharSet(hps, IDF_NORMAL);
  77.     GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm);
  78.     ptPos.x = 0;
  79.     ptPos.y = rectl.yTop - fm.lMaxBaselineExt;
  80.     for (i = 0; papszString[i] != NULL; i++)
  81.         TypesetGpiString(hps, papszString[i], &ptPos, rectl.xRight);
  82.  
  83.     /* destroy our fonts */
  84.     GpiSetCharSet(hps, LCID_DEFAULT);
  85.     GpiDeleteSetId(hps, IDF_NORMAL);
  86.     GpiDeleteSetId(hps, IDF_ITALIC);
  87.     GpiDeleteSetId(hps, IDF_BOLD);
  88.     GpiDeleteSetId(hps, IDF_BOLDITALIC);
  89.  
  90.     /* calculate boundary information */
  91.     prectlBoundary->xLeft = 0;
  92.     prectlBoundary->yTop = rectl.yTop;
  93.     prectlBoundary->xRight = rectl.xRight;
  94.     prectlBoundary->yBottom = ptPos.y;
  95.  
  96.     /* close metafile */
  97.     GpiAssociate(hps, NULLHANDLE);
  98.     GpiDestroyPS(hps);
  99.     return (DevCloseDC(hdc));
  100. }
  101. #endif
  102.  
  103.  
  104. #ifndef GENERIC
  105. void TypesetGpiString(HPS hps, char *pszString, POINTL *pptlPos, int iWidth)
  106. /*
  107.  * Typeset a string using some simple HTML and display it using GPI calls.
  108.  *
  109.  * HPS hps        - the handle to the presentation space on which to typeset
  110.  * char *pszString    - the string to be typeset
  111.  * POINTL *pptlPos    - starting position; end position is returned here
  112.  * int iWidth        - the paragraph width
  113.  */
  114. {
  115.     char        *pszCurrent, *pszNext;
  116.     char        szChunk[30], szWord[30];
  117.     int        aiFont[30], aiStart[30];
  118.     int        iMacro, iTag, i;
  119.     long        lWordWidth;
  120.     BOOL        bHTMLEnd, bGotWord;
  121.     BOOL        bItalics, bBold;
  122.     POINTL        aptlExtent[TXTBOX_COUNT];
  123.     POINTL        ptlCursor;
  124.     FONTMETRICS    fm;
  125.  
  126.     pszCurrent = pszString;
  127.     bHTMLEnd = FALSE;
  128.     bItalics = bBold = FALSE;
  129.     GpiSetCharSet(hps, IDF_NORMAL);
  130.     GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm);
  131.     memcpy(&ptlCursor, pptlPos, sizeof(POINTL));
  132.     i = 0;
  133.     aiFont[0] = IDF_NORMAL;
  134.     aiStart[0] = 0;
  135.     while (!bHTMLEnd) {
  136.  
  137.         /* construct the next word we have to typeset */
  138.         szWord[0] = '\0';
  139.         bGotWord = FALSE;
  140.         lWordWidth = 0;
  141.         aiFont[0] = aiFont[i];
  142.         i = 0;
  143.         while (!bGotWord) {
  144.             iTag = 0;
  145.             switch (HTMLGetNextChunk(pszCurrent, szChunk, &pszNext)) {
  146.                 case HTML_WORD_END:
  147.                     bGotWord = TRUE;
  148.                 case HTML_WORD_MID:
  149.                     strcat(szWord, szChunk);
  150.                     GpiQueryTextBox(hps, strlen(szChunk), szChunk, TXTBOX_COUNT, aptlExtent);
  151.                     lWordWidth += aptlExtent[4].x - aptlExtent[1].x;
  152.                     break;
  153.  
  154.                 case HTML_TAG_END:
  155.                     bGotWord = TRUE;
  156.                 case HTML_TAG_MID:
  157.                     switch (iTag = HTMLParseTag(szChunk)) {
  158.                         case HTML_PARAGRAPH:
  159.                         case HTML_LINEBREAK:
  160.                             bGotWord = TRUE;
  161.                             break;
  162.  
  163.                         case HTML_ITALICS_START:
  164.                             bItalics = TRUE;
  165.                             GpiSetCharSet(hps, (bBold)? IDF_BOLDITALIC : IDF_ITALIC);
  166.                             aiFont[++i] = (bBold)? IDF_BOLDITALIC : IDF_ITALIC;
  167.                             aiStart[i] = strlen(szWord);
  168.                             break;
  169.  
  170.                         case HTML_ITALICS_END:
  171.                             bItalics = FALSE;
  172.                             GpiSetCharSet(hps, (bBold)? IDF_BOLD : IDF_NORMAL);
  173.                             aiFont[++i] = (bBold)? IDF_BOLD : IDF_NORMAL;
  174.                             aiStart[i] = strlen(szWord);
  175.                             break;
  176.  
  177.                         case HTML_BOLD_START:
  178.                             bBold = TRUE;
  179.                             GpiSetCharSet(hps, (bItalics)? IDF_BOLDITALIC : IDF_BOLD);
  180.                             aiFont[++i] = (bItalics)? IDF_BOLDITALIC : IDF_BOLD;
  181.                             aiStart[i] = strlen(szWord);
  182.                             break;
  183.  
  184.                         case HTML_BOLD_END:
  185.                             bBold = FALSE;
  186.                             GpiSetCharSet(hps, (bItalics)? IDF_ITALIC : IDF_NORMAL);
  187.                             aiFont[++i] = (bItalics)? IDF_ITALIC : IDF_NORMAL;
  188.                             aiStart[i] = strlen(szWord);
  189.                             break;
  190.                     }
  191.                     break;
  192.  
  193.                 case HTML_MACRO_END:
  194.                     bGotWord = TRUE;
  195.                 case HTML_MACRO_MID:
  196.                     if ((iMacro = HTMLParseMacro(szChunk)) != -1)
  197.                         sprintf(szChunk, "%c", iMacro);
  198.                     strcat(szWord, szChunk);
  199.                     GpiQueryTextBox(hps, strlen(szChunk), szChunk, TXTBOX_COUNT, aptlExtent);
  200.                     lWordWidth += aptlExtent[4].x - aptlExtent[1].x;
  201.                     break;
  202.  
  203.                 case HTML_END:
  204.                     bGotWord = TRUE;
  205.                     bHTMLEnd = TRUE;
  206.                     break;
  207.             }
  208.             pszCurrent = pszNext;
  209.         }
  210.  
  211.  
  212.         if (szWord[0] != '\0')
  213.             if ((ptlCursor.x + lWordWidth) <= iWidth) {
  214.                 /* the word will fit on this line */
  215.                 TypesetGpiWord(hps, szWord, aiFont, aiStart, i + 1, &ptlCursor);
  216.                 ptlCursor.x += lWordWidth + fm.lAveCharWidth;
  217.             } else {
  218.                 /* the word needs to go on a new line */
  219.                 ptlCursor.x = 0;
  220.                 ptlCursor.y -= fm.lMaxBaselineExt;
  221.                 TypesetGpiWord(hps, szWord, aiFont, aiStart, i + 1, &ptlCursor);
  222.                 ptlCursor.x += lWordWidth + fm.lAveCharWidth;
  223.             }
  224.         if ((iTag == HTML_PARAGRAPH) || (iTag == HTML_LINEBREAK)) {
  225.             /* insert a new line */
  226.             ptlCursor.x = 0;
  227.             ptlCursor.y -= fm.lMaxBaselineExt;
  228.             if (iTag == HTML_PARAGRAPH)
  229.                 ptlCursor.y -= fm.lMaxBaselineExt;
  230.         }
  231.     }
  232.  
  233.     /* copy the finishing position into ptlPos to be returned */
  234.     memcpy(pptlPos, &ptlCursor, sizeof(POINTL));
  235. }
  236. #endif
  237.  
  238.  
  239. #ifndef GENERIC
  240. void TypesetGpiWord(HPS hps, char *pszWord, int *aiFont, int *aiStart, int n, POINTL *pptlPos)
  241. /*
  242.  * Print a single word using GPI calls.
  243.  *
  244.  * HPS hps        - the handle of the presentation space to print on
  245.  * char *pszWord    - the word to print
  246.  * int *aiFont        - the vector containing IDs of fonts to use
  247.  * int *aiStart        - the vector containing the starting positions for fonts
  248.  * int n        - the length of aiFont and aiStart
  249.  * POINTL *pptlPos    - the point to print the word at
  250.  */
  251. {
  252.     char    szBlock[30], *pszCursor;
  253.     POINTL    aptlExtent[TXTBOX_COUNT];
  254.     POINTL    ptlCursor;
  255.     int    i, k;
  256.  
  257.     memcpy(&ptlCursor, pptlPos, sizeof(POINTL));
  258.     pszCursor = pszWord;
  259.     for (i = 0; i < n; i++)
  260.         if (pszCursor[0] != '\0') {
  261.             if (i == (n - 1)) {
  262.                 strcpy(szBlock, pszCursor);
  263.                 k = strlen(pszCursor);
  264.             } else {
  265.                 if ((k = aiStart[i + 1] - aiStart[i]) > 0) {
  266.                     strncpy(szBlock, pszCursor, k);
  267.                     szBlock[k] = '\0';
  268.                     pszCursor += k;
  269.                 }
  270.             }
  271.             if (k > 0) {
  272.                 GpiSetCharSet(hps, aiFont[i]);
  273.                 GpiCharStringAt(hps, &ptlCursor, strlen(szBlock), szBlock);
  274.                 GpiQueryTextBox(hps, strlen(szBlock), szBlock, TXTBOX_COUNT, aptlExtent);
  275.                 memcpy(&ptlCursor, aptlExtent + 4, sizeof(POINTL));
  276.             }
  277.         }
  278. }
  279. #endif
  280.  
  281.  
  282. char *TypesetASCII(char **papszString, int iWidth)
  283. /*
  284.  * Typeset an HTML string into ASCII text, simplifying the HTML where neccessary.
  285.  * Space for the string will be allocated.
  286.  *
  287.  * char **papszString    - sequence of strings to be typeset, NULL to terminate
  288.  * int iWidth        - the maximum width of a line of text (0 if no maximum)
  289.  *
  290.  * Returns        - NULL if memory could not be allocated
  291.  *              pointer to the typeset string otherwise
  292.  */
  293. {
  294.     char    *pszRet, *pszCurrent, *pszNext;
  295.     char    szChunk[30], szWord[30];
  296.     int    i, iCounter, iTag, iMacro;
  297.     int    bHTMLEnd, bGotWord, bFirst;
  298.  
  299.     /* allocate memory */
  300.     iCounter = 0;
  301.     for (i = 0; papszString[i] != NULL; i++)
  302.         iCounter += strlen(papszString[i]);
  303.     if ((pszRet = (char *)malloc(iCounter)) == NULL)
  304.         return (NULL);
  305.  
  306.     /* typeset the strings */
  307.     iCounter = 0;
  308.     for (i = 0; papszString[i] != NULL; i++) {
  309.         pszCurrent = papszString[i];
  310.         bHTMLEnd = 0;
  311.         while (!bHTMLEnd) {
  312.  
  313.             /* construct the next word to typeset */
  314.             szWord[0] = '\0';
  315.             bGotWord = 0;
  316.             while (!bGotWord) {
  317.                 iTag = 0;
  318.                 switch (HTMLGetNextChunk(pszCurrent, szChunk, &pszNext)) {
  319.                     case HTML_WORD_END:
  320.                         bGotWord = 1;
  321.                     case HTML_WORD_MID:
  322.                         strcat(szWord, szChunk);
  323.                         break;
  324.  
  325.                     case HTML_TAG_END:
  326.                         bGotWord = 1;
  327.                     case HTML_TAG_MID:
  328.                         switch (iTag = HTMLParseTag(szChunk)) {
  329.                             case HTML_LINEBREAK:
  330.                             case HTML_PARAGRAPH:
  331.                                 bGotWord = 1;
  332.                                 break;
  333.  
  334.                             /*
  335.                              * We can't render any font changes
  336.                              * in ASCII, so HTML_ITALICS_*, etc.,
  337.                              * are ignored here.
  338.                              */
  339.                         }
  340.                         break;
  341.  
  342.                     case HTML_MACRO_END:
  343.                         bGotWord = 1;
  344.                     case HTML_MACRO_MID:
  345.                         bGotWord = 1;
  346.                         if ((iMacro = HTMLParseMacro(szChunk)) != -1)
  347.                             sprintf(szChunk, "%c", iMacro);
  348.                         strcat(szWord, szChunk);
  349.                         break;
  350.  
  351.                     case HTML_END:
  352.                         bGotWord = 1;
  353.                         bHTMLEnd = 1;
  354.                         break;
  355.                 }
  356.                 pszCurrent = pszNext;
  357.             }
  358.  
  359.             /* add the word to the output string */
  360.             if (szWord[0] != '\0') {
  361.                 bFirst = iCounter == 0;
  362.                 iCounter += strlen(szWord) + 1;
  363.                 if ((iCounter <= iWidth) || (iWidth == 0)) {
  364.                     /* the word will fit on this line */
  365.                     if (!bFirst)
  366.                         strcat(pszRet, " ");
  367.                     strcat(pszRet, szWord);
  368.                 } else {
  369.                     /* the word needs to go on a new line */
  370.                     strcat(pszRet, "\n");
  371.                     strcat(pszRet, szWord);
  372.                     iCounter = strlen(szWord);
  373.                 }
  374.             }
  375.  
  376.             /* check for user-enforced new-lines */
  377.             if (iTag == HTML_LINEBREAK) {
  378.                 strcat(pszRet, "\n");
  379.                 iCounter = 0;
  380.             } else if (iTag == HTML_PARAGRAPH) {
  381.                 strcat(pszRet, "\n\n");
  382.                 iCounter = 0;
  383.             }
  384.         }
  385.     }
  386.  
  387.     return (pszRet);
  388. }
  389.