home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Libraries / VideoToolbox 94.11.17 / VideoToolboxSources / StringBounds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-02  |  4.5 KB  |  145 lines  |  [TEXT/KAHL]

  1. /*
  2. StringBounds.c
  3.  
  4.     void StrBounds(char *str,Rect *bounds,long *count);
  5.     void StringBounds(const unsigned char *string,Rect *bounds,long *count);
  6. StrBounds accepts a C string. StringBounds accepts a pascal string.
  7. Both routines count--and compute the minimum bounding rectangle for--all the pixels that
  8. would be set black by calling DrawString with the given string with the
  9. current port's font, size, and style. Coordinates in the *bounds rect are
  10. relative to the current pen position. If no pixels would be set then *bounds is
  11. set to the empty rect (0,0,0,0). The current port is left untouched.
  12.  
  13. The measurements are based on a full rendering of the string in a private
  14. GWorld, without any clipping.
  15.  
  16. The bounds and count arguments are optional; they may be replaced by NULL.
  17.  
  18.     void CharBounds(char a,Rect *bounds,long *count);
  19. Creates a one-char string and calls StringBounds().
  20.  
  21. NOTES
  22.  
  23. bounds->right need not exactly equal the value returned by StringWidth(s),
  24. because StringWidth returns the displacement of the pen position, and some (e.g.
  25. italic) characters extend beyond that, while others (e.g. comma) extend less
  26. far. Similarly, bounds->left need not always be zero.
  27.  
  28. By QuickDraw's convention, each pixel is considered to lie below and to the
  29. right of the point that is used to address it. The bounding rectangle for a
  30. pixel at x,y, is SetRect(&r,x,y,x+1,y+1).
  31.  
  32. The code assumes ForeColor is black and that TextMode is srcOr, which are the 
  33. default settings for the GWorld that we create.
  34.  
  35. HISTORY:
  36. 1/17/94 dgp wrote it, based on discussion with Bart Farell and Manoj Gunwani.
  37. 2/22/94    dgp    added count argument, and made both bounds and count optional.
  38. 2/27/94    dgp since this routine is typically called repeatedly I save time
  39.             (0.2 s per call) by only allocating the GWorld once, and never
  40.             freeing it. It is reused on subsequent calls, resized appropriately
  41.             if necessary.
  42. 9/5/94 dgp removed assumption in printf's that int==short.
  43. 11/2/94 dgp discovered that the clip rect may be nonsense after calling
  44. UpdateGWorld, so I set it equal to the portRect.
  45. */
  46. #include "VideoToolbox.h"
  47. #include <assert.h>
  48. #define SHOW_BITMAPS 0    // for debugging
  49.  
  50. void CharBounds(char a,Rect *boundsPtr,long *countPtr)
  51. {
  52.     unsigned char string[]="\pA";
  53.     
  54.     string[1]=a;
  55.     StringBounds(string,boundsPtr,countPtr);
  56. }
  57.  
  58. void StrBounds(char *s,Rect *boundsPtr,long *countPtr)
  59. {
  60.     StringBounds(c2pstr(s),boundsPtr,countPtr);
  61.     p2cstr((unsigned char *)s);
  62. }
  63.  
  64. void StringBounds(const unsigned char *s,Rect *boundsPtr,long *countPtr)
  65. {
  66.     static GWorldPtr our=NULL;
  67.     GWorldPtr old;
  68.     GDHandle oldDevice;
  69.     FontInfo f;
  70.     Rect r;
  71.     register unsigned long *pix;
  72.     register int x,y;
  73.     register long count=0;
  74.     int n;
  75.     int error;
  76.     Rect bounds;
  77.     char string[40];
  78.  
  79.     assert(StackSpace()>4000);
  80.     GetFontInfo(&f);
  81.     SetRect(&r,0,-f.ascent,StringWidth(s),f.descent);    // nominal size
  82.     InsetRect(&r,-(f.widMax+2),-(f.leading+2));         // add margin
  83.  
  84.     // draw string into a new GWorld
  85.     if(our!=NULL){
  86.         DisposeGWorld(our);
  87.         our=NULL;
  88.     }
  89.     if(our==NULL){
  90.         error=NewGWorld(&our,1,&r,NULL,NULL,keepLocal|useTempMem);
  91.         if(error)error=NewGWorld(&our,1,&r,NULL,NULL,keepLocal);
  92.     }else{
  93.         error=UpdateGWorld(&our,1,&r,NULL,NULL,clipPix);
  94.         assert(EqualRect(&r,&our->portRect));
  95.         assert((**our->clipRgn).rgnSize==10);
  96.         (**our->clipRgn).rgnBBox=our->portRect;
  97.     }
  98.     if(error)PrintfExit("StringBounds: NewGWorld/UpdateGWorld error %d.\n",error);
  99.     GetGWorld(&old,&oldDevice);
  100.     SetGWorld(our,NULL);
  101.     TextFace(old->txFace);
  102.     TextFont(old->txFont);
  103.     TextSize(old->txSize);
  104.     EraseRect(&our->portRect);
  105.     MoveTo(0,0);
  106.     DrawString(s);
  107.     SetGWorld(old,oldDevice);
  108.     if(SHOW_BITMAPS){
  109.         PrintfGWorld(our);
  110.         gets(string);
  111.     }
  112.  
  113.     // measure the bounding box, and count the black pixels
  114.     r=our->portRect;
  115.     SetRect(&bounds,r.right,r.bottom,r.left,r.top);
  116.     n=r.right-r.left;
  117.     pix=(unsigned long *)malloc(n*sizeof(*pix));
  118.     if(pix==NULL)PrintfExit("%s line %d: Couldn't allocate %ld bytes.\n"
  119.         ,__FILE__,__LINE__,n*sizeof(long));
  120.     SetGWorld(our,NULL);
  121.     OffsetRect(&bounds,-r.left,-r.top);
  122.     for(y=0;y<r.bottom-r.top;y++){
  123.         GetPixelsQuickly(r.left,r.top+y,pix,n);
  124.         for(x=n-1;x>=0;x--)if(pix[x]!=0){
  125.             count++;
  126.             if(x<bounds.left)bounds.left=x;
  127.             if(x>=bounds.right)bounds.right=x+1;
  128.             if(y<bounds.top)bounds.top=y;
  129.             if(y>=bounds.bottom)bounds.bottom=y+1;
  130.         }
  131.     }
  132.     OffsetRect(&bounds,r.left,r.top);
  133.     if(SHOW_BITMAPS){
  134.         InvertRect(&bounds);
  135.         PrintfGWorld(our);
  136.         gets(string);
  137.     }
  138.     SetGWorld(old,oldDevice);
  139.     if(EmptyRect(&bounds))SetRect(&bounds,0,0,0,0);
  140.     free(pix);    
  141. //    DisposeGWorld(our);
  142.     if(boundsPtr!=NULL)*boundsPtr=bounds;
  143.     if(countPtr!=NULL)*countPtr=count;
  144. }
  145.