OOFILE  1.9
oofdraw.cpp
Go to the documentation of this file.
1 // oofDraw.cpp - Implementation for oofCurrentDraw - holder of current
3 // drawing info & other drawing state and measurement classes
4 //
5 // COPYRIGHT 1996-1998 A.D. Software, All rights reserved
6 
7 #include "oofpch_g.h" // for precompilation of graph files
8 
9 #include "oofDraw.h"
10 
11 #ifndef H_OOF1
12  #include "oof1.h"
13 #endif
14 
15 #include <ctype.h>
16 #include <assert.h>
17 
18 #ifdef _Macintosh
19  #include <QuickdrawText.h>
20  #include <Resources.h>
21 #endif
22 
23 
24 #ifdef _Windows
25 
26  #ifndef H_OOFDIB
27  #include "oofDIB.h"
28  #endif
29 
30  #ifndef _INC_WINDOWSX
31  #include "windowsx.h"
32  #endif
33 
34 #endif // _Windows
35 
36 #ifdef OOF_MEM_DEBUG_LAST_INCLUDE
37  #include OOF_MEM_DEBUG_LAST_INCLUDE
38 #endif
39 
40 #ifndef OOF_NO_STDLIB
41  #ifndef std
42  using namespace std;
43  #endif
44 #endif
45 
46 #ifdef _Windows
47 
48 
49 HDC oofCurrentDraw::shdc = 0;
50 HDC oofCurrentDraw::sInfoDC = 0;
51 oofCurrentDraw oofCurrentDraw::sCurrentDraw; // single instance to guarantee destruction of resources
52 int oofCurrentDraw::sX = 0;
53 int oofCurrentDraw::sY = 0;
54 
55 // showdib prototypes & defs
56 /* struct to be passed in for the SETDIBSCALING printer escape */
57 typedef struct {
58  SHORT ScaleMode;
59  SHORT dx, dy;
60 } DIBPARAMS;
61 
62 // Old MFC Mac portability macros
63 #define SWAPWORD(x) x
64 #define SWAPLONG(x) x
65 
66 #define MAXREAD 32768 /* Number of bytes to be read during */
67  /* each read operation. */
68 /* Header signatutes for various resources */
69 #define BFT_ICON 0x4349 /* 'IC' */
70 #define BFT_BITMAP 0x4d42 /* 'BM' */
71 #define BFT_CURSOR 0x5450 /* 'PT' */
72 
73 /* macro to determine if resource is a DIB */
74 #define ISDIB(bft) ((bft) == BFT_BITMAP)
75 
76 /* Macro to align given value to the closest DWORD (unsigned long ) */
77 #define ALIGNULONG(i) ((i+3)/4*4)
78 
79 /* Macro to determine to round off the given value to the closest byte */
80 #define WIDTHBYTES(i) ((i+31)/32*4)
81 
82 #define PALVERSION 0x300
83 #define MAXPALETTE 256 /* max. # supported palette entries */
84 
85 HANDLE OpenDIB (LPSTR szFile);
86 VOID FreeDib();
87 INT InitDIB();
88 BOOL StretchDibBlt (
89  HDC hdc,
90  INT x,
91  INT y,
92  INT dx,
93  INT dy,
94  HANDLE hdib,
95  INT x0,
96  INT y0,
97  INT dx0,
98  INT dy0,
99  LONG rop);
100 
101 VOID PrintDIB (
102  HDC hDC,
103  INT x,
104  INT y,
105  INT dx,
106  INT dy);
107 
108 DWORD PASCAL lread (
109  INT fh,
110  VOID FAR *pv,
111  DWORD ul);
112 
113 
114 HANDLE ReadDibBitmapInfo (INT fh);
115 BOOL DibInfo (
116  HANDLE hbi,
117  LPBITMAPINFOHEADER lpbi);
118 HPALETTE CreateDibPalette (HANDLE hbi);
119 HPALETTE CreateBIPalette (LPBITMAPINFOHEADER lpbi);
120 WORD DibNumColors (VOID FAR * pv);
121 WORD PaletteSize (VOID FAR * pv);
122 VOID ReadBitMapFileHeaderandConvertToDwordAlign(HFILE fh,
123  LPBITMAPFILEHEADER pbf,
124  LPDWORD lpdwoff);
125 INT ErrMsg (PSTR sz,...);
126 BOOL DrawBitmap (
127  HDC hdc,
128  INT x,
129  INT y,
130  HBITMAP hbm,
131  DWORD rop);
132 BOOL DrawBitmapScaled (
133  HDC hdc,
134  INT x,
135  INT y,
136  INT drawWidth,
137  INT drawHeight,
138  HBITMAP hbm,
139  DWORD rop);
140 HBITMAP BitmapFromDib (
141  HANDLE hdib,
142  HPALETTE hpal);
143 
144 // showdib variables
145 
146 DIBPARAMS DIBParams; /* params for the SETSCALING escape */
147 CHAR achFileName[128];
148 DWORD dwOffset;
149 NPLOGPALETTE pLogPal;
150 HPALETTE hpalSave = NULL;
151 HANDLE hInst ;
152 RECT rcClip;
153 static HCURSOR hcurSave;
154 
155 BOOL fPalColors = FALSE; /* TRUE if the current DIB's color table */
156  /* contains palette indexes not rgb values */
157 UINT nAnimating = 0; /* Palette animation count */
158 WORD UpdateCount = 0;
159 
160 BOOL bUpdateColors = TRUE; /* Directly update screen colors */
161 BOOL bDIBToDevice = FALSE; /* Use SetDIBitsToDevice() to BLT data. */
162 BOOL bNoUgly = FALSE; /* Make window black on a WM_PALETTEISCHANGING */
163 BOOL bLegitDraw = FALSE; /* We have a valid bitmap to draw */
164 
165 CHAR szBitmapExt[] = "*.BMP; *.DIB; *.RLE"; /* possible file extensions */
166 WORD wTransparent = TRANSPARENT; /* Mode of DC */
167 CHAR szAppName[] = "ShowDIB" ; /* App. name */
168 
169 HPALETTE hpalCurrent = NULL; /* Handle to current palette */
170 HANDLE hdibCurrent = NULL; /* Handle to current memory DIB */
171 HBITMAP hbmCurrent = NULL; /* Handle to current memory BITMAP */
172 HANDLE hbiCurrent = NULL; /* Handle to current bitmap info struct */
173 HWND hWndApp; /* Handle to app. window */
174 
175 
176 // end of showdib variables
177 
178 
179 
180 // -------------------------------------------------------
181 // o o f C u r r e n t D r a w
182 // -------------------------------------------------------
183 oofCurrentDraw::oofCurrentDraw()
184 {
185 }
186 
187 
188 oofCurrentDraw::~oofCurrentDraw()
189 {
190  deleteInfoDC();
191  assert(shdc==0); // whoever last used us as a container should have cleaned up their private dc
192 }
193 
194 
195 void
196 oofCurrentDraw::makeInfoDC()
197 {
198  if (!sInfoDC) {
199  sInfoDC = ::CreateIC("DISPLAY", NULL, NULL, NULL);
200  assert(sInfoDC);
201  makeDC72dpiLogical(sInfoDC);
202  }
203 }
204 
205 
206 void
207 oofCurrentDraw::makeDC72dpiLogical(HDC hdc)
208 {
209  // stuff because we want to work in 72dpi pts
210  // and LOGPIXELSY always returns 96 regardless of actual dpi
211  if (hdc==0)
212  return; // **** early exit - assume caller resetting their DC or similar action
213 
214  const int horzres = ::GetDeviceCaps(hdc, HORZRES);
215  const int horzsize = ::GetDeviceCaps(hdc, HORZSIZE); // always mm
216  const int vertres = ::GetDeviceCaps(hdc, VERTRES);
217  const int vertsize = ::GetDeviceCaps(hdc, VERTSIZE);
218 
219  const double devHorDPI = 25.4*horzres/horzsize;
220  const double devVertDPI = 25.4*vertres/vertsize;
221 
222  const int horDP10i = 10 * devHorDPI;
223  const int vertDP10i = 10 * devVertDPI;
224  assert(horDP10i<32767); // safe for Win95
225  assert(vertDP10i<32767); // safe for Win95
226  SIZE oldViewExtent, oldWindowExtent;
227  ::SetMapMode(hdc, MM_ANISOTROPIC);
228  ::SetViewportExtEx(hdc, horDP10i, vertDP10i, &oldViewExtent);
229  ::SetWindowExtEx(hdc, 720, 720, &oldWindowExtent);
230 }
231 
232 
233 void
234 oofCurrentDraw::deleteInfoDC()
235 {
236  if (sInfoDC)
237  ::DeleteDC(sInfoDC);
238  sInfoDC = 0;
239 }
240 
241 
242 BOOL
243 oofCurrentDraw::moveToEx(HDC hdc, int X, int Y, LPPOINT lpPoint)
244 {
245  BOOL ret = true;
246 
247  if (hdc) {
248  ret = ::MoveToEx(hdc, X, Y, lpPoint);
249 
250  } // if a DC
251  if (lpPoint != NULL) { // update the point with our cached last locn as metafile doesn't
252  lpPoint->x = sX;
253  lpPoint->y = sY;
254  }
255  sX = X; // update our location regardless - important for recording draws on Windows
256  sY = Y;
257 
258  return ret;
259 }
260 
261 
262 void
263 oofCurrentDraw::resetCoordinates()
264 {
265  sX = 0;
266  sY = 0;
267 }
268 
269 
270 void
271 oofCurrentDraw::setCurrentDC(HDC hdc)
272 {
273  if (hdc==0)
274  oofTextDrawer::cleanupFont();
275  shdc = hdc;
276  makeDC72dpiLogical(hdc);
277 }
278 #endif // _Windows
279 
280 
281 // -------------------------------------------------------
282 // o o f T e x t D r a w e r
283 // -------------------------------------------------------
284 
285 #ifdef _Windows
286 HFONT oofTextDrawer::sFont = NULL;
287 #endif
288 int oofTextDrawer::sLastCharHeight, oofTextDrawer::sLastCharHeightRequest, oofTextDrawer::sCurrentFontSize;
289 
290 
291 #ifdef _Macintosh
292 bool
294 {
295  bool retVal;
296 
297  if (textSize == -1)
298  textSize = 10;
299 //david debug 990810
300 // if (textSize==sCurrentFontSize)
301 // return true; // early return optimisation
302 //david debug 990810
303  ::TextSize(textSize);
304  retVal = true;
305  sCurrentFontSize = textSize;
306  return retVal;
307 }
308 
309 
310 #elif defined _Windows
311 BOOL
312 oofTextDrawer::setFontSize(int textSize)
313 {
314  bool retVal;
315 
316  if (textSize == -1)
317  textSize = 10;
318 
319  if (textSize==sCurrentFontSize)
320  return true; // early return optimisation
321 
322  HDC dc = oofCurrentDraw::getCurrentDC();
323 
324  if (sFont) {
325  LOGFONT lf;
326 
327  // Create the new font based on the currently selected one
328  ::GetObject(sFont, sizeof(LOGFONT), &lf);
329  HDC ic = oofCurrentDraw::getInfoDC();
330  assert(ic);
331  const int pixelsY = ::GetDeviceCaps(ic, LOGPIXELSY);
332  lf.lfHeight = -textSize; // -MulDiv(textSize, pixelsY, 72);
333  HFONT newFont = oofTextDrawer::createFontIndirect(&lf);
334  if (dc)
335  selectFont(dc, newFont); // also sets ic
336 
337  retVal = true;
338  }
339  else
340  retVal = false;
341  sCurrentFontSize = textSize;
342  return retVal;
343 }
344 #endif // OS
345 
346 #ifdef _Macintosh
347 bool
349 
350 {
351  bool retVal = false;
352 #if defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON!=0
353  GrafPtr currentPort;
354  ::GetPort(&currentPort);
355  short theSize = GetPortTextFont (currentPort);
356 #else
357  short theSize = (qd.thePort->txSize);
358  short theFont = (qd.thePort->txFont);
359 #endif
360  if(theSize == sCurrentFontSize)
361  retVal = true;
362  return retVal;
363 }
364 
365 #elif defined _Windows // andy not much of an idea how to do this
366 bool
368 {
369  bool retVal = false;
370  return true; // david debug to be fixed
371 }
372 #endif // OS
373 
374 
375 
376 
377 int
379 {
380  int charHeight = 0;
381 
382  if (textSize==sLastCharHeightRequest)
383  return sLastCharHeight; // early exit - cached value
384 
385 #ifdef _Macintosh
386  if (setFontSize(textSize)) {
387  FontInfo fi;
388  ::GetFontInfo(&fi);
389  charHeight = (fi.ascent+fi.descent+fi.leading);
390  }
391 #elif defined _Windows
392  if (textSize == -1)
393  textSize = 10; // UGLY HARDCODED VALUE
394 
395  HDC ic = oofCurrentDraw::getInfoDC();
396 
397  if (sFont != NULL) {
398  LOGFONT lf;
399  ::GetObject(sFont, sizeof(LOGFONT), &lf);
400  lf.lfHeight = -textSize; // -MulDiv(textSize, ::GetDeviceCaps(ic, LOGPIXELSY), 72);
401 
402  HFONT hTestFont = oofTextDrawer::createFontIndirect(&lf);
403  HFONT hOldFont = (HFONT)::SelectObject(ic, hTestFont);
404 
405  TEXTMETRIC tm;
406  memset(&tm, 0, sizeof(TEXTMETRIC));
407  ::GetTextMetrics(ic, &tm);
408 
409 // select old or system font so our testFont is freed up for deletion
410  if (hOldFont)
411  ::SelectObject(ic, hOldFont);
412  else
413  ::SelectObject(ic, GetStockFont(SYSTEM_FONT));
414 
415  ::DeleteObject(hTestFont);
416  charHeight = tm.tmHeight + tm.tmExternalLeading;
417  }
418 #endif
419 
420  // update cached values
421  sLastCharHeightRequest = textSize;
422  sLastCharHeight = charHeight;
423  return charHeight;
424 }
425 
426 
427 #ifdef _Windows
428 void
429 oofTextDrawer::cleanupFont()
430 {
431  sLastCharHeightRequest = 0; // just to be safe
432  sCurrentFontSize = 0;
433 // select stock fonts into the IC and DC so we can delete our cached font, if any
434  if (sFont) {
435  HFONT sysFont = GetStockFont(SYSTEM_FONT);
436  {
437  HDC ic = oofCurrentDraw::getInfoDC();
438  if (ic)
439  ::SelectObject(ic, sysFont);
440  }
441  {
442  HDC dc = oofCurrentDraw::getCurrentDC();
443  if (dc)
444  ::SelectObject(dc, sysFont);
445  }
446  ::DeleteObject(sFont);
447  sFont = 0;
448  }
449 }
450 
451 
452 BOOL
453 oofTextDrawer::textOutCP(HDC hdc, LPCTSTR lpString, int cbString, int textSize)
454 {
455  const BOOL retVal = textOut(hdc, oofCurrentDraw::x(), oofCurrentDraw::y(), lpString, cbString);
456  oofCurrentDraw::incX(textSize);
457  return retVal;
458 }
459 
460 
461 BOOL
462 oofTextDrawer::textOutCP(HDC hdc, const oofString& inStr, int textSize)
463 {
464  const BOOL retVal = textOut(hdc, oofCurrentDraw::x(), oofCurrentDraw::y(), inStr);
465  oofCurrentDraw::incX(textSize);
466  return retVal;
467 }
468 
469 
470 BOOL
471 oofTextDrawer::textOut(HDC hdc, int x, int y, LPCTSTR lpString, int cbString)
472 {
473  const BOOL retVal = ::TextOut(hdc, x, y, lpString, cbString);
474  return retVal;
475 }
476 
477 
478 BOOL
479 oofTextDrawer::textOut(HDC hdc, int x, int y, const oofString& inStr)
480 {
481  const BOOL retVal = ::TextOut(hdc, x, y, inStr, inStr.length());
482  return retVal;
483 }
484 
485 
486 SIZE
487 oofTextDrawer::getTextExtent(const oofString& text)
488 {
489  HDC ic = oofCurrentDraw::getInfoDC();
490  assert(ic != NULL);
491  assert(sFont != NULL);
492 
493  HFONT hOldFont = (HFONT)::SelectObject(ic, sFont);
494  assert(hOldFont);
495 
496 /* AD980519 not win32s compliant
497  SIZE size;
498  ::GetTextExtentPoint32(ic, text, text.length(), &size);
499 */
500  SIZE size;
501  const unsigned long textLen = text.length();
502  if (textLen==0)
503  size.cx = 0;
504  else {
505  DWORD retSize = ::GetTabbedTextExtent(ic, text, textLen, 0, 0 /* no tab positions */);
506  if (retSize==0) {
507  DWORD lastErr = ::GetLastError(); // so we can check in debugger
508  assert(!"Error in oofTextDrawer::getTextExtent() getting text size"); //lint !e506 constant Boolean
509  }
510  else
511  size.cx = LOWORD(retSize); // assume don't care about cy - NOT YET IMPLEMENTED rewrite this call to return X value alone
512  }
513  ::SelectObject(ic, hOldFont);
514 
515  return size;
516 }
517 
518 
519 HFONT
520 oofTextDrawer::selectFont(HDC hdc, HFONT hFont)
521 {
522 // NOT YET IMPLEMENTED - compare hFont and sFont content to avoid changing font if the same
523 // (just what IS the overhead on repeated font creation anyway?)
524 
525  if (sFont==hFont)
526  return hFont; // trivial exit
527 
528  sLastCharHeightRequest = 0; // clear caches - don't know if new font is same size
529  sCurrentFontSize = 0; // important flag to avoid resetting size
530 
531  HFONT prevICfont=0, prevDCfont=0;
532  if (hdc)
533  prevDCfont = (HFONT) ::SelectObject(hdc, hFont);
534  HDC currentIC = oofCurrentDraw::getInfoDC();
535  if (currentIC==hdc)
536  prevICfont = prevDCfont;
537  else { // also implies not NULL
538  assert(currentIC);
539  prevICfont = (HFONT) ::SelectObject(currentIC, hFont);
540  }
541 
542  if (sFont) { // can delete old font after freeing from above
543  // assert(sFont==prevICfont || sFont==prevDCfont); // user could trigger this by direct font setting in their code
544  // so this is a good check that code called by report-writer or graph uses oofTextDrawer
545  // REMOVED ASSERTION 990428 as it triggers in sample reports when go to print
546  ::DeleteObject(sFont); // VITAL - avoid leaks!!!!!
547  }
548  sFont = hFont;
549  return prevICfont;
550 }
551 
552 
553 HFONT
554 oofTextDrawer::createFontIndirect(const LOGFONT* lpLogFont)
555 {
556 // incorporates dreadful bloody hack to cope with NT printing for now
557  // to match the standard interface we have to take a const pointer
558  // therefore we copy it if we need to hack values
559  HFONT ret;
560  LOGFONT copiedFont; // it's on the stack, don't fuss with heap alloc
561  bool changedFontDesc = false;
562  /*
563  switch (oofRuntimeEnv::runtimeEnv()) {
564  case oofRuntimeEnv::WinNT:
565  changedFontDesc = true;
566  memcpy(&copiedFont, lpLogFont, sizeof(LOGFONT));
567  // only change fonts that specify char height, ie: negative heights
568  if (copiedFont.lfHeight < -4) {// arbitrary, but seems reasonable
569  const int reduceBy = (copiedFont.lfHeight-0)/7; // ie: 2 for 14, 3 for 21
570  copiedFont.lfHeight -=reduceBy;
571  }
572  copiedFont.lfOutPrecision = OUT_OUTLINE_PRECIS; // TT or other outline fonts
573  copiedFont.lfQuality = PROOF_QUALITY; // not allowed to scale raster fonts
574  break;
575 
576  case oofRuntimeEnv::Win32s:
577  // NOT YET IMPLEMENTD - dunno if we need to adjust yet
578  break;
579 
580  default:
581  ;
582  }
583  */
584  if (changedFontDesc)
585  ret = ::CreateFontIndirect(&copiedFont);
586  else
587  ret = ::CreateFontIndirect(lpLogFont);
588  return ret;
589 }
590 
591 
592 int
593 oofTextDrawer::getCurrentFontDesc(LOGFONT* lf)
594 {
595  return ::GetObject(sFont, sizeof(LOGFONT), lf);
596 }
597 
598 
599 HFONT
600 oofTextDrawer::getCurrentFont()
601 {
602  return sFont;
603 }
604 
605 
606 #endif // _Windows
607 
608 
609 // -------------------------------------------------------
610 // o o f T e x t S i z e r
611 // -------------------------------------------------------
612 // A simple sizer which wraps to multiple rows
613 // This is designed to be used one-on-one by objects
614 // as it calculates and retains a LineStarts array
615 // for when you draw the text.
616 
617 
618 
619 // ---------------------------------------------------------------------------
620 // oofTextSizer - Default Constructor
621 // ---------------------------------------------------------------------------
622 
624  mMeasureArray(0),
625  mLineStarts(0),
626  mLineLengths(0),
627  mMeasureLen(0),
628  mNumRows(0),
629  mLineStartsCells(0)
630 {}
631 
632 
633 // ---------------------------------------------------------------------------
634 // ~oofTextSizer
635 // ---------------------------------------------------------------------------
636 // Destructor
637 
639 {
640  delete[] mMeasureArray;
641  delete[] mLineStarts;
642  delete[] mLineLengths;
643 }
644 
645 
646 // ---------------------------------------------------------------------------
647 // StoreLineStart
648 // ---------------------------------------------------------------------------
649 
650 void
651 oofTextSizer::StoreLineStart(unsigned long inLineStart)
652 {
653  if (mLineStartsCells <= mNumRows) {
654  mLineStartsCells = mNumRows+4; // minor optim - go up in four's
655  unsigned long* newLines = new unsigned long[mLineStartsCells];
656  unsigned long* newLengths = new unsigned long[mLineStartsCells];
657  for (unsigned long i=0; i < mNumRows; i++) {
658  newLines[i] = mLineStarts[i]; // copy words
659  newLengths[i] = mLineLengths[i];
660  }
661  delete[] mLineStarts;
662  delete[] mLineLengths;
663  mLineStarts = newLines;
664  mLineLengths = newLengths;
665  }
666  mLineStarts[mNumRows] = inLineStart;
667  mNumRows++;
668 }
669 
670 
671 // ---------------------------------------------------------------------------
672 // StoreLineLength
673 // ---------------------------------------------------------------------------
674 
675 void
676 oofTextSizer::StoreLineLength(unsigned long inLineLength)
677 {
678  // always called after StoreLineStart, so mNumRows has been advanced
679  assert(mLineStartsCells >= mNumRows);
680  mLineLengths[mNumRows-1] = inLineLength;
681 }
682 
683 
684 // ---------------------------------------------------------------------------
685 // SkipWhiteForward
686 // ---------------------------------------------------------------------------
687 
688 void
690  const char *inValue, // C string
691  unsigned long& ioWordStart,
692  unsigned long& ioCharsLeft) const
693 {
694  if (ioCharsLeft==0)
695  return;
696 
697  unsigned long ix = ioWordStart;
698  unsigned long pastLastChar = ix + ioCharsLeft;
699  while ((ix < pastLastChar) && /* isspace(inValue[ix]) */ ((inValue[ix]==' ') || (inValue[ix]=='\t')) /* Ken - modification to stop skipping linebreaks !*/)
700  ++ix; // skip to start of partial word
701  if (ix == pastLastChar) {
702  ioCharsLeft = 0;
703  ioWordStart = 0;
704  }
705  else {
706  ioCharsLeft -= (ix-ioWordStart);
707  ioWordStart = ix;
708  }
709 }
710 
711 
712 // ---------------------------------------------------------------------------
713 // CalculateWrapping
714 // ---------------------------------------------------------------------------
715 // WARNING: must have a port and the correct text traits current to work!
716 
717 // wraps at the first character that fits in the current col width
718 // optionally trimming off a partial word if we do truncation
719 //
720 // WARNING: must have a port and the correct text traits current to work!
721 //
722 
723 
724 
764 void
766  const char *inValue, // C string
767  unsigned long inItemSize,
768  unsigned long inColWidth,
769  bool inWillTruncWords)
770 {
771 #ifdef OOF_GRAPH_DEBUG_DUMP
772  ofstream myStream("CalculateWrapping state",ios::app); // 990806 david debug
773 
774  myStream << " --- WRAPPING STATE "<< inValue << endl;
775 
776  describe(myStream);
777  myStream << " input string: "<< inValue << endl;
778  myStream << " Font size: " << qd.thePort->txSize << endl;
779  myStream << " Text style: " << qd.thePort->txFace << endl;
780  myStream << " Space extra: " << qd.thePort->spExtra << endl;
781  myStream << " font: " << qd.thePort->txFont << endl;
782  myStream << " --- END WRAPPING STATE "<< inValue << endl<< endl;
783 
784 #endif
785 
786 
787  const unsigned short kMaxCharsInSingleLine = 500; // limit to avoid too much remeasuring
788  mNumRows = 0;
789  if (!inValue || inItemSize==0)
790  return; // trivial case - 0 rows as set above
791 
792  unsigned long charsLeftInString = inItemSize;
793  unsigned long measureFrom = 0;
794  SkipWhiteForward(inValue, measureFrom, charsLeftInString); // skip leading white space,
795 
796  if (charsLeftInString==0)
797  return; // trivial case of totally empty line, just whitespace
798 
799  unsigned short maxCharsToMeasure;
800 // maintain array used for pixel measurement
801  if (charsLeftInString > kMaxCharsInSingleLine)
802  maxCharsToMeasure = kMaxCharsInSingleLine;
803  else
804  maxCharsToMeasure = charsLeftInString;
805  if (mMeasureLen <=maxCharsToMeasure ) {
806  delete[] mMeasureArray;
807  mMeasureLen = maxCharsToMeasure+1;
808  mMeasureArray = new unsigned short[mMeasureLen];
809  assert(mMeasureArray);
810  }
811 
812  while (charsLeftInString > 0) {
813  // check if line starts with CR, CRLF etc. - is blank line
814  unsigned long truncAtChar = 0;
815  unsigned long termLen = 0;
816  if(inValue[measureFrom]==0x0D) { // CR - for PC and Mac
817  if (inValue[measureFrom+1]==0x0A)
818  termLen = 2;
819  else
820  termLen = 1;
821  }
822  else {
823  if (inValue[measureFrom]==0x0A) // LF - for Unix
824  termLen = 1;
825  }
826 
827  StoreLineStart(measureFrom); // we know it's not white space so regardless of how we end, this is where we start
828  if (termLen) { // processing a line terminator, maybe at the start of a blank line or after an earlier line
829  StoreLineLength(0);
830  measureFrom += termLen;
831  charsLeftInString -= termLen;
832  }
833  else { // some text on line
834  // prescan forward to find terminator, to cut down on how much text we might measure
835  // (makes a big difference with many short lines in a block)
836 
837  // reset maxCharsToMeasure otherwise stays at length of first short terminated line
838  if (charsLeftInString > kMaxCharsInSingleLine)
839  maxCharsToMeasure = kMaxCharsInSingleLine;
840  else
841  maxCharsToMeasure = charsLeftInString;
842 
843  unsigned long terminatorAt = 0;
844  for (unsigned short preOffset=0; preOffset<maxCharsToMeasure; preOffset++) {
845  const char preCh = inValue[preOffset+measureFrom];
846  if (preCh==0x0D || preCh==0x0A) {
847  maxCharsToMeasure = preOffset; // just shortens limit used below
848  terminatorAt = preOffset; // used as flag below for quick optimisation
849  break;
850  }
851  } // loop pre-scanning for terminators
852 // now measure the text on the line
853 #ifdef _Macintosh
854  ::MeasureText(maxCharsToMeasure, &inValue[measureFrom], mMeasureArray);
855 #elif defined _Windows
856 // WARNING - under Windows we get a width for the CR and LF characters (I suspect the width of
857 // the 'missing character' box) unlike the Mac where they have 0 width
858 
859  // Provide equivalent of Mac API call MeasureText(), taking account of proportional fonts
860  HDC hdc = oofCurrentDraw::getInfoDC(); // works with old metafile, but doesn't wrap
861  // get cumulative widths each iteration, which takes advantage of font ligature measurement etc.
862  // the Mac call starts with a 0 cell - each cell is the accumulated length to its position
863  mMeasureArray[0] = 0;
864  const char* const startFrom = &inValue[measureFrom];
865  const int numChars = maxCharsToMeasure;
866  for (int cumChar=1; cumChar<=numChars; cumChar++) {
867  DWORD retSize = ::GetTabbedTextExtent(hdc, startFrom,
868  cumChar, 0, 0 /* no tab positions */
869  );
870  if (retSize==0) {
871  DWORD lastErr = ::GetLastError(); // so we can check in debugger
872  assert(!"Error in oofTextSizer::CalculateWrapping() getting text size"); //lint !e506 constant Boolean
873  }
874  else {
875  int cumLen = LOWORD(retSize);
876  mMeasureArray[cumChar] = cumLen;
877  if (cumLen>inColWidth) {
878  maxCharsToMeasure = cumChar; // optimisation - shorten comparison loop below
879  truncAtChar = cumChar;
880  break; // EXIT LOOP - WE JUST EXCEEDED COL WIDTH
881  }
882  } // no error measuring
883  } // loop string measuring cumulatively
884 
885 
886 /* nice approach that is unfortunately not supported under win32s
887  // get all widths in one hit, which takes advantage of font ligature measurement etc.
888  // the Mac call starts with a 0 cell - each cell is the accumulated length to its position
889  SIZE stringSize;
890  int charsThatFit = maxCharsToMeasure;
891  int* measureArray = new int[maxCharsToMeasure+1];
892  measureArray[0] = 0;
893  BOOL measuredOK = ::GetTextExtentExPoint(hdc, &inValue[measureFrom],
894  maxCharsToMeasure, inColWidth, &charsThatFit, &measureArray[1], &stringSize
895  );
896  if (!measuredOK)
897  DWORD lastErr = ::GetLastError();
898  if (charsThatFit < maxCharsToMeasure)
899  maxCharsToMeasure = charsThatFit;
900 */
901 
902 /* old inaccurate way
903  int charWidth;
904  {
905  int n, accumWidth;
906  for (n = 0, accumWidth = 0; n < maxCharsToMeasure; mMeasureArray[n] = accumWidth, accumWidth += charWidth, n++)
907  ::GetCharWidth(hdc, inValue[measureFrom + n], inValue[measureFrom + n], &charWidth);
908  // Put the width of the last character in
909  mMeasureArray[n] = accumWidth;
910  }
911 */
912 #endif // OS
913 
914  // quick optimisation - if we hit a terminator above it is quite likely that the entire line
915  // will fit the column, so just check the total length to see
916 #ifdef _Macintosh
917  if ((terminatorAt==0) || (mMeasureArray[terminatorAt] > inColWidth) ){
918 #elif defined _Windows
919  // in our measurement we will have stopped (on Windows) if we pass the limit, so may have adjusted maxCharsToMeasure
920  if ((terminatorAt==0) || ((terminatorAt <= maxCharsToMeasure) && (mMeasureArray[terminatorAt] > inColWidth)) ){
921 #endif // OS
922  // scan forward through text for line terminators
923  // checking to see if we pass the pixel length allowed
924  const unsigned long lengthLeft = maxCharsToMeasure; // local const for optimal loop
925  for (unsigned long i=0; i<lengthLeft; i++) {
926  if (mMeasureArray[i] > inColWidth) { // just went past allowed pixel length
927  truncAtChar = i;
928  break;
929  }
930  const char nextCh = inValue[i+measureFrom];
931  if (nextCh==0x0D || nextCh==0x0A) {
932  terminatorAt = i;
933  break;
934  }
935  } // loop through text looking for terminators
936  } // if hit terminator in prescan and entire line is wider than column
937 
938  if (truncAtChar) { // truncated within terminator or remainder of line, don't care which
939  // have to scan back from where we exceeded pixel length
940  // to find a word on which to wrap
941  truncAtChar--;
942  assert(mMeasureArray[truncAtChar] <= inColWidth); // because we stop just as we exceed
943  if (inWillTruncWords) {
944  // start truncation from one char past fitted string, in case
945  // word ended exactly at the boundary
946  unsigned long nextWordStart;
947  truncAtChar = TruncateTrailingWord(&inValue[measureFrom], truncAtChar, nextWordStart); // ret is currently 1-based
948  if (nextWordStart==0) // haven't calculated it yet as boundary was in white space
949  nextWordStart = truncAtChar+1; // can assume at least one whitespace char exists
950  measureFrom += nextWordStart; // saves time skipping whitespace later
951  StoreLineLength(mMeasureArray[truncAtChar] );
952  charsLeftInString -= truncAtChar+1;
953  } // inWillTruncWords so had to find word boundary
954  SkipWhiteForward(inValue, measureFrom, charsLeftInString); // skip leading white space before next line
955  }
956  else if (terminatorAt) { // hit terminator after at least one character before line was too long
957  StoreLineLength(mMeasureArray[terminatorAt]);
958  measureFrom += terminatorAt;
959  if (termLen==0) {
960  termLen = 1; // guaranteed a terminator due to checks above setting terminatorAt
961  if((inValue[measureFrom]==0x0D) && (inValue[measureFrom+1]==0x0A))
962  termLen = 2;
963  }
964  measureFrom += termLen;
965  charsLeftInString -= terminatorAt+termLen;
966  }
967  else { // remainder of line fits
968  StoreLineLength(mMeasureArray[maxCharsToMeasure]);
969  charsLeftInString = 0;
970  }
971  } // line with some text
972  } // loop lines
973 
974  #ifdef OOF_GRAPH_DEBUG_DUMP
975  describe(myStream);
976  myStream.close();
977  #endif
978 }
979 
980 
981 // ---------------------------------------------------------------------------
982 // describe
983 // ---------------------------------------------------------------------------
984 // describe state of drawing engine
985 
986 void
987 oofTextSizer::describe(ostream& os) const
988 {
989  int index;
990  os << "-=-=-=-= ooftext sizer state -=-=-=-=" << endl
991  << "address of this: " << (unsigned long) this
992  << " mMeasureLen : " << mMeasureLen
993  << " mNumRows : " << mNumRows
994  << " mLineStartsCells : " << mLineStartsCells
995 
996 
997  << " mMeasureArray : " ;
998  for(index = 0;index < mMeasureLen;index++)
999  os << mMeasureArray[index] <<", ";
1000  os<< " mLineStarts : ";
1001  for(index = 0;index < mNumRows;index++)
1002  os << mLineStarts[index] <<", ";
1003  os << endl
1004  << " mLineLengths : " ;
1005  for(index = 0;index < mNumRows;index++)
1006  os << mLineLengths[index] <<", ";
1007 
1008  os << endl << "-=-=-=-= sizer state -=-=-=-=" << endl << endl;
1009 }
1010 
1011 
1012 // ---------------------------------------------------------------------------
1013 // TruncateTrailingWord
1014 // ---------------------------------------------------------------------------
1015 // trimming off a partial word if we do truncation
1016 
1017 unsigned long
1019  const char *inValue, // C string
1020  unsigned long inEndWord,
1021  unsigned long& outNextWordStart) const
1022 {
1023  unsigned long ix = inEndWord;
1024  while (ix > 0 && !isspace(inValue[ix]))
1025  --ix; // skip to start of partial word
1026 
1027  if (ix==0) {
1028  outNextWordStart = inEndWord+1;
1029  return inEndWord; // were part-way through remaining word on line
1030  }
1031 
1032  if (ix < inEndWord) // were part-way through a word
1033  outNextWordStart = ix+1;
1034  else
1035  outNextWordStart = 0;
1036 
1037  while (ix > 0 && isspace(inValue[ix]))
1038  --ix; // skip preceding whitespace
1039 
1040  if (ix > 0) // was at least one word before partial word
1041  inEndWord = ix+1;
1042  else
1043  if (isspace(inValue[1])) // degenerate case "*<space>BLAH"
1044  inEndWord = 1;
1045 
1046  return inEndWord;
1047 }
1048 
1049 
1050 
1051 
1052 // -------------------------------------------------------
1053 // o o f S i z e d T e x t A r r a y
1054 // -------------------------------------------------------
1055 oofSizedTextArray::oofSizedTextArray(unsigned short numItems) :
1056  mSizers(0),
1057  mStrings(0),
1058  mCount(0),
1059  mMaxNumRows(0)
1060 {
1061  if (numItems)
1062  initSizers(numItems);
1063 }
1064 
1065 
1067 {
1068  delete [] mSizers;
1069  delete [] mStrings;
1070 }
1071 
1072 
1073 void
1074 oofSizedTextArray::initSizers(unsigned short numItems)
1075 {
1076 // NOTE
1077 // later could use Prototype pattern - init with a prototype sizer
1078 // that we duplicate below, rather than hardcoding the type of sizer
1079 
1080  assert (mCount==0); // should only call once if didn't alloc size at construction
1081  mCount = numItems;
1082  mSizers = new oofTextSizer[numItems];
1083  mStrings = new OOF_String[numItems];
1084 }
1085 
1086 
1087 oofString&
1088 oofSizedTextArray::text(unsigned short i) const
1089 {
1090  return mStrings[i];
1091 }
1092 
1093 
1094 const unsigned long*
1095 oofSizedTextArray::GetLineStarts(unsigned short index) const
1096 {
1097  assert(index < mCount);
1098  return mSizers[index].GetLineStarts();
1099 }
1100 
1101 
1102 const unsigned long*
1103 oofSizedTextArray::GetLineLengths(unsigned short index) const
1104 {
1105  assert(index < mCount);
1106  return mSizers[index].GetLineLengths();
1107 }
1108 
1109 
1110 unsigned short
1111 oofSizedTextArray::GetNumRows(unsigned short index) const
1112 {
1113  assert(index < mCount);
1114  return mSizers[index].GetNumRows();
1115 }
1116 
1117 
1118 void
1120  unsigned short inColWidth,
1121  bool inTruncWords)
1122 {
1123  assert(index < mCount);
1124  const char* value = mStrings[index];
1125  unsigned short itemSize = mStrings[index].length();
1126  mSizers[index].CalculateWrapping(value, itemSize, inColWidth, inTruncWords);
1127  unsigned short numRows = GetNumRows(index);
1128  if (numRows > mMaxNumRows)
1129  mMaxNumRows = numRows; // entire reason for this wrapper is maintaining our max!!
1130 }
1131 
1132 
1133 // -------------------------------------------------------
1134 // o o f P i c t
1135 // -------------------------------------------------------
1136 #ifdef _Macintosh
1137 oofPict::oofPict(unsigned long PICTresourceID) :
1138  mFromFile(false),
1139  mLoaded(false),
1140  mResID(PICTresourceID),
1141  mJPEG(0)
1142 {
1143 }
1144 
1145 #elif defined _Windows
1146 oofPict::oofPict(int BITMAPresourceID) :
1147  mFromFile(false),
1148  mLoaded(false),
1149  mResID(BITMAPresourceID),
1150  mDIB(0),
1151  mJPEG(0)
1152 {
1153  // uncomment all the following when oofDIB can load from resource
1154 // mDIB = new oofDIB;
1155 // mDIB->loadResource(BITMAPresourceID);
1156  assert(!"oofDIB not yet able to load from resource"); //lint !e506 constant Boolean
1157 // mLoaded = true; // created mDIB without error
1158 // mHeight = mDIB->height();
1159 // mWidth = mDIB->width();
1160 }
1161 
1162 oofPict::oofPict(HBITMAP copiedBitmap, HDC usingHDC) :
1163  mFromFile(false),
1164  mLoaded(false),
1165  mResID(0),
1166  mDIB(0),
1167  mJPEG(0)
1168 {
1169  mDIB = new oofDIB;
1170  mDIB->copyFromHBITMAP(copiedBitmap, usingHDC);
1171  mLoaded = true; // created mDIB without error
1172  mHeight = mDIB->height();
1173  mWidth = mDIB->width();
1174 }
1175 
1176 #endif
1177 
1178 
1180  mHeight(0),
1181  mWidth(0),
1182  mFile(inFile),
1183  mFromFile(true),
1184  mLoaded(false),
1185  mJPEG(0)
1186 #ifdef _Windows
1187  ,mDIB(0)
1188 #endif
1189 {
1190 }
1191 
1192 
1194  mHeight(rhs.mHeight),
1195  mWidth(rhs.mWidth),
1196  mFile(rhs.mFile),
1197  mFromFile(rhs.mFromFile),
1198  mLoaded(rhs.mLoaded),
1199  mResID(rhs.mResID),
1200  mJPEG(rhs.mJPEG)
1201 #ifdef _Macintosh
1202  ,mGWorld(rhs.mGWorld)
1203 #elif defined _Windows
1204  ,mDIB(rhs.mDIB)
1205 #endif
1206 {
1207  #ifdef _Windows
1208  if (mDIB)
1209  mDIB->incRefs();
1210  #endif
1211  if (mJPEG)
1212  mJPEG->incRefs();
1213 }
1214 
1215 
1217 {
1218  // Mac:
1219  // GWorld is automatically taken care of by the concrete OOF_GWorldOwner member mGWorld
1220 
1221  // Windows:
1222  // The Bitmap is only loaded when drawing takes place, all memory
1223  // used is deleted immediately after drawing.
1224  #ifdef _Windows
1225  if (mDIB)
1226  mDIB->decRefs();
1227  #endif
1228  if (mJPEG)
1229  mJPEG->decRefs();
1230 }
1231 
1232 
1233 oofPict*
1235 {
1236  return new oofPict(*this);
1237 }
1238 
1239 
1240 unsigned long
1242 {
1243  if (!mLoaded)
1244  Load();
1245  assert(mHeight>0);
1246  return mHeight;
1247 }
1248 
1249 
1250 unsigned long
1252 {
1253  if (!mLoaded)
1254  Load();
1255  assert(mWidth>0);
1256  return mWidth;
1257 }
1258 
1259 
1260 
1261 oofString
1263 {
1264  if (mFromFile)
1265  return mFile.path();
1266  else {
1267  oofString ret;
1268 #ifdef _Macintosh
1269  // mResID only defined on Mac - can't load Windows picts from resource number
1270  ret.convertNumber(mResID, "Picture Resource ID: %d");
1271 #endif
1272  return ret;
1273  }
1274 }
1275 
1276 
1277 #ifdef _Macintosh
1278 
1281 void
1282 oofPict::Load() // _Macintosh
1283 {
1284  mHeight = 0;
1285  mWidth = 0;
1286 
1287 
1288  CGrafPtr curPort;
1289  GDHandle curDevice;
1290  PixMapHandle offPix;
1291  Rect pictRect;
1292  PicHandle pict;
1293  GWorldPtr localGWorld;
1294 
1295  // Save current graphics device settings
1296  ::GetGWorld( &curPort, &curDevice );
1297 
1298  // Get a handle to the picture
1299  if (mFromFile)
1300  pict = readPict(mFile);
1301  else
1302  pict = ::GetPicture( mResID );
1303 
1304  pictRect.top = 0;
1305  pictRect.bottom = (**pict).picFrame.bottom - (**pict).picFrame.top;
1306  pictRect.left = 0;
1307  pictRect.right = (**pict).picFrame.right - (**pict).picFrame.left;
1308 
1309  mHeight = pictRect.bottom;
1310  mWidth = pictRect.right;
1311 
1312  // Create GWorld
1313  const OSErr newErr = ::NewGWorld( &localGWorld, 0, &pictRect, nil, curDevice, nil );
1314 
1315  // Draw into GWorld
1316  if( newErr==noErr ) {
1317  offPix = GetGWorldPixMap( localGWorld );
1318  if( ::LockPixels( offPix ) ) {
1319  ::SetGWorld( localGWorld, nil );
1320 
1321  #if defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON!=0
1322  Rect theFrame;
1323  ::GetPortBounds(localGWorld, &theFrame);
1324  ::EraseRect( &theFrame );
1325  #else
1326  ::EraseRect( &(localGWorld->portRect) );
1327  #endif
1328  ::DrawPicture( pict, &pictRect );
1329  ::UnlockPixels( offPix );
1330  }
1331  }
1332 
1333  // Restore the graphics device settings
1334  ::SetGWorld( curPort, curDevice );
1335 
1336  // Remove memory for picture
1337  if( pict != NULL)
1338  ::ReleaseResource( (Handle)pict );
1339 
1340  // Save the pointer to the concrete member
1341  mGWorld = localGWorld;
1342 
1343  mLoaded = true;
1344 }
1345 
1346 
1347 PicHandle
1348 oofPict::readPict(const oofFileRef& inRef) // _Macintosh
1349 {
1350  assert(inRef.isValid());
1351  short fRef;
1352  const OSErr openErr = ::FSpOpenDF(&inRef.spec(), fsRdPerm, &fRef);
1353  long fileLen;
1354  const long kPicHeaderLen = 512;
1355  ::GetEOF(fRef, &fileLen);
1356  ::SetFPos(fRef, fsFromStart, kPicHeaderLen);
1357  long pictLen = fileLen - kPicHeaderLen;
1358  Handle ret = ::NewHandle(pictLen);
1359  if (ret) {
1360  ::HLock(ret);
1361  const OSErr readErr = ::FSRead(fRef, &pictLen, *ret);
1362  ::HUnlock(ret);
1363  }
1364  ::FSClose(fRef);
1365  return (PicHandle)ret;
1366 }
1367 
1368 
1369 void
1370 oofPict::draw(int x, int y, int right, int bottom, bool onPrinter) // _Macintosh
1371 {
1372  if (!mLoaded)
1373  Load();
1374 
1375 
1376  CGrafPtr curPort;
1377  GDHandle curDevice;
1378  PixMapHandle offPix;
1379  Rect srcRect, destRect;
1380 
1381  GWorldPtr theGWorld = mGWorld.gWorld();
1382 
1383  if( theGWorld ){
1384 
1385  // Save current graphics device settings
1386  ::GetGWorld( &curPort, &curDevice );
1387 
1388  offPix = ::GetGWorldPixMap(theGWorld);
1389 
1390  if( LockPixels( offPix ) ){
1391  // from Load, we've set mHeight and mWidth to actual pic dimensions
1392  srcRect.top = 0;
1393  srcRect.left = 0;
1394  srcRect.bottom = mHeight;
1395  srcRect.right = mWidth;
1396  const short inWidth = right - x;
1397  const short inHeight = bottom - y;
1398  short drawWidth = mWidth;
1399  short drawHeight = mHeight;
1400  if (mWidth>inWidth) { // scale down
1401  drawWidth = inWidth;
1402  drawHeight = mHeight * inWidth/mWidth;
1403  }
1404  else if (mWidth<inWidth) { // centre smaller picture horizontally, leave at top vertically
1405  x += (inWidth - mWidth)/2;
1406  }
1407 
1408  destRect.top = y;
1409  destRect.left = x;
1410  destRect.bottom = y+drawHeight;
1411  destRect.right = x+drawWidth;
1412 
1413 #if defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON!=0
1414  const BitMap* theBitMap = GetPortBitMapForCopyBits (curPort);
1415  CopyBits( (BitMap *)*offPix,
1416  theBitMap ,
1417  &srcRect,
1418  &destRect,
1419  srcCopy, NULL );
1420 #else
1421  ::CopyBits( (BitMap *)*offPix,
1422  &((GrafPtr)curPort)->portBits,
1423  &srcRect,
1424  &destRect,
1425  srcCopy, NULL );
1426 #endif
1427  ::UnlockPixels( offPix );
1428  }
1429  } // have a gWorld
1430 }
1431 
1432 
1433 #elif defined _Windows
1434 void
1435 oofPict::draw(int x, int y, int right, int bottom, bool onPrinter, HDC drawDC) // _Windows
1436 {
1437  assert(right>=x);
1438  assert(bottom>=y);
1439  const int drawWidth = right - x;
1440  const int drawHeight = bottom - y;
1441 
1442  if (mDIB) { // was loaded from RAM
1443  mDIB->draw(x, y, drawWidth, drawHeight, onPrinter, drawDC);
1444  return;
1445  }
1446 
1447  if (!mLoaded)
1448  Load();
1449  else { // hack to make picture bands draw, otherwise they only appear on redraws
1450  FreeDib();
1451  Load();
1452  }
1453  // draw appropriately
1454  if (onPrinter) {
1455  PrintDIB(drawDC, x, y, drawWidth, drawHeight);
1456  }
1457  else { // draw on screen
1458  if (hbmCurrent && !bDIBToDevice)
1459  DrawBitmapScaled (drawDC, x, y, drawWidth, drawHeight, hbmCurrent, SRCCOPY);
1460  }
1461  FreeDib();
1462  mLoaded = false; // initial test - always unload after drawing
1463 }
1464 
1469 void
1470 oofPict::Load() // _Windows
1471 {
1472  mLoaded = true;
1473 // load the bitmap
1474  strcpy(achFileName, mFile.path());
1475  InitDIB();
1476 
1477  BITMAPINFOHEADER bi;
1478  DibInfo (hbiCurrent, &bi);
1479  mHeight = bi.biHeight;
1480  mWidth = bi.biWidth;
1481 }
1482 
1483 #endif // _Windows
1484 
1485 
1486 void
1488 {
1489  if (mJPEG)
1490  mJPEG->decRefs(); // forget old one
1491  mJPEG = new oofSharedBLOB;
1492  inFile.readBinary(mJPEG);
1493 // mLoaded = true;
1494 // mHeight =
1495 // mWidth =
1496 }
1497 
1498 
1499 // -------------------------------------------------------
1500 // O O F _ m i x P i c t O w n e r
1501 // -------------------------------------------------------
1503  mPict(inPict)
1504 {
1505 }
1506 
1507 
1509 {
1510  if (rhs.mPict)
1511  mPict = rhs.mPict->clone();
1512  else
1513  mPict = 0;
1514 }
1515 
1516 
1518 {
1519  delete mPict;
1520 }
1521 
1522 
1523 
1524 // -------------------------------------------------------
1525 // O O F _ G W o r l d O w n e r
1526 // -------------------------------------------------------
1527 #ifdef _Macintosh
1528 
1530  mGWorld(0)
1531 {
1532  mRefs = new unsigned long(1);
1533 }
1534 
1536 {
1537  if (*mRefs<=1) {
1538  if( mGWorld != NULL) {
1539  DisposeGWorld( mGWorld );
1540  mGWorld = NULL;
1541  }
1542  delete mRefs;
1543  }
1544  else
1545  {
1546  (*mRefs)--;
1547  }
1548 }
1549 
1551  mGWorld( rhs.mGWorld ),
1552  mRefs(rhs.mRefs)
1553 {
1554  (*mRefs)++;
1555 }
1556 
1558 OOF_GWorldOwner::operator=(GWorldPtr adoptedGWorld)
1559 {
1560  mGWorld = adoptedGWorld;
1561  return *this;
1562 }
1563 
1564 #endif // _Macintosh
1565 
1566 
1567 
1568 #ifdef _Windows
1569 
1570 // -------------------------------------------------------
1571 // S H O W D I B M e t h o d s
1572 // -------------------------------------------------------
1573 DWORD PASCAL lread (
1574  INT fh,
1575  VOID FAR *pv,
1576  DWORD ul)
1577 {
1578  DWORD ulT = ul;
1579  BYTE* hp = (BYTE*)pv;
1580 
1581  while (ul > (DWORD)MAXREAD) {
1582  if (_lread(fh, (LPSTR)hp, (UINT)MAXREAD) != MAXREAD)
1583  return 0;
1584  ul -= MAXREAD;
1585  hp += MAXREAD;
1586  }
1587  if (_lread(fh, (LPSTR)hp, (UINT)ul) != (UINT)ul)
1588  return 0;
1589  return ulT;
1590 }
1591 
1592 
1593 
1594 /****************************************************************************
1595  * *
1596  * FUNCTION : InitDIB(hWnd) *
1597  * *
1598  * PURPOSE : Reads a DIB from a file, obtains a handle to it's *
1599  * BITMAPINFO struct., sets up the palette and loads the DIB. *
1600  * *
1601  * RETURNS : TRUE - DIB loads ok *
1602  * FALSE - otherwise *
1603  * *
1604  ****************************************************************************/
1605 INT InitDIB()
1606 {
1607  HFILE fh;
1608  LPBITMAPINFOHEADER lpbi;
1609  WORD FAR * pw;
1610  INT i;
1611  BITMAPINFOHEADER bi;
1612  OFSTRUCT of;
1613 
1614  FreeDib();
1615 
1616  /* Open the file and get a handle to it's BITMAPINFO */
1617 
1618  fh = OpenFile(achFileName, (LPOFSTRUCT)&of, (UINT)OF_READ);
1619  if (fh == -1) {
1620  ErrMsg("Can't open file '%ls'", (LPSTR)achFileName);
1621  return FALSE;
1622  }
1623  hbiCurrent = ReadDibBitmapInfo(fh);
1624 
1625  dwOffset = _llseek(fh, 0L, (UINT)SEEK_CUR);
1626  _lclose(fh);
1627 
1628  if (hbiCurrent == NULL) {
1629  ErrMsg("%ls is not a Legitimate DIB File!", (LPSTR)achFileName);
1630  return FALSE;
1631  }
1632  DibInfo(hbiCurrent,&bi);
1633 
1634  /* Set up the palette */
1635  hpalCurrent = CreateDibPalette(hbiCurrent);
1636  if (hpalCurrent == NULL) {
1637  ErrMsg("CreatePalette() Failed");
1638  return FALSE;
1639  }
1640 
1641  /* Convert the DIB color table to palette relative indexes, so
1642  * SetDIBits() and SetDIBitsToDevice() can avoid color matching.
1643  * We can do this because the palette we realize is identical
1644  * to the color table of the bitmap, ie the indexes match 1 to 1
1645  *
1646  * Now that the DIB color table is palette indexes not RGB values
1647  * we must use DIB_PAL_COLORS as the wUsage parameter to SetDIBits()
1648  */
1649  lpbi = (tagBITMAPINFOHEADER*)GlobalLock(hbiCurrent); //(VOID FAR *)GlobalLock(hbiCurrent);
1650  if (lpbi->biBitCount <= 24) {
1651  fPalColors = TRUE;
1652 
1653  pw = (WORD FAR *)((LPSTR)lpbi + lpbi->biSize);
1654 
1655  for (i=0; i<(INT)lpbi->biClrUsed; i++)
1656  *pw++ = (WORD)i;
1657  }
1658  GlobalUnlock(hbiCurrent);
1659  bLegitDraw = TRUE;
1660 
1661  /* If the input bitmap is not in RGB FORMAT the banding code will
1662  * not work! we need to load the DIB bits into memory.
1663  * if memory DIB, load it all NOW! This will avoid calling the
1664  * banding code.
1665  */
1666  hdibCurrent = OpenDIB(achFileName);
1667 
1668  /* If the RLE could not be loaded all at once, exit gracefully NOW,
1669  * to avoid calling the banding code
1670  */
1671  if ((bi.biCompression != BI_RGB) && !hdibCurrent){
1672  ErrMsg ("Could not load RLE!");
1673  FreeDib();
1674  return FALSE;
1675  }
1676 
1677  if (hdibCurrent && !bDIBToDevice){
1678  hbmCurrent = BitmapFromDib(hdibCurrent,hpalCurrent);
1679  if (!hbmCurrent){
1680  ErrMsg ("Could not create bitmap!");
1681  FreeDib();
1682  return FALSE;
1683  }
1684  }
1685 // SizeWindow(hWnd);
1686 
1687  return TRUE;
1688 }
1689 
1690 
1691 /****************************************************************************
1692  * *
1693  * FUNCTION : PrintDIB(HDC hDC, int x, int y, int dx, int dy)*
1694  * *
1695  * PURPOSE : Set the DIB bits to the printer DC. *
1696  * *
1697  ****************************************************************************/
1698 VOID PrintDIB (
1699  HDC hDC,
1700  INT x,
1701  INT y,
1702  INT dx,
1703  INT dy)
1704 
1705 {
1706  BITMAPINFOHEADER bi;
1707  INT dibX, dibY;
1708  INT dibDX, dibDY;
1709 
1710  if (!bLegitDraw)
1711  return;
1712 
1713  DibInfo (hbiCurrent, &bi);
1714 
1715  if (IsRectEmpty (&rcClip)){
1716  dibX = 0;
1717  dibY = 0;
1718  dibDX = (INT)bi.biWidth;
1719  dibDY = (INT)bi.biHeight;
1720  }
1721  else{
1722  dibX = rcClip.left;
1723  dibY = (INT)bi.biHeight - 1 - rcClip.bottom;
1724  dibDX = rcClip.right - rcClip.left;
1725  dibDY = rcClip.bottom - rcClip.top;
1726  }
1727 
1728  if (hdibCurrent){
1729  /* Stretch the DIB to printer DC */
1730  StretchDibBlt ( hDC,
1731  x,
1732  y,
1733  dx,
1734  dy,
1735  hdibCurrent,
1736  dibX,
1737  dibY,
1738  dibDX,
1739  dibDY,
1740  SRCCOPY);
1741  }
1742 /* else if (achFileName[0]) {
1743 
1744  SetMapMode (hDC, MM_ANISOTROPIC);
1745  (VOID)SetViewportOrgEx (hDC, x, y, NULL);
1746  (VOID)SetViewportExtEx (hDC, dx, dy, NULL);
1747 
1748  BandDIB (hWnd, hDC, 0, 0);
1749  }
1750 */
1751 }
1752 
1753 /****************************************************************************
1754  * *
1755  * FUNCTION : FreeDib(void) *
1756  * *
1757  * PURPOSE : Frees all currently active bitmap, DIB and palette objects *
1758  * and initializes their handles. *
1759  * *
1760  ****************************************************************************/
1761 VOID FreeDib()
1762 {
1763  if (hpalCurrent)
1764  DeleteObject(hpalCurrent);
1765 
1766  if (hbmCurrent)
1767  DeleteObject(hbmCurrent);
1768 
1769  if (hdibCurrent)
1770  GlobalFree(hdibCurrent);
1771 
1772  if (hbiCurrent && hbiCurrent != hdibCurrent)
1773  GlobalFree(hbiCurrent);
1774 
1775  fPalColors = FALSE;
1776  bLegitDraw = FALSE;
1777  hpalCurrent = NULL;
1778  hdibCurrent = NULL;
1779  hbmCurrent = NULL;
1780  hbiCurrent = NULL;
1781  SetRectEmpty (&rcClip);
1782 }
1783 
1784 
1785 /****************************************************************************
1786  * *
1787  * FUNCTION : StretchDibBlt( HDC hdc, *
1788  * int x, int y, *
1789  * int dx, int dy, *
1790  * HANDLE hdib, *
1791  * int x0, int y0, *
1792  * int dx0, int dy0, *
1793  * LONG rop) *
1794  * *
1795  * PURPOSE : Draws a bitmap in CF_DIB format, using StretchDIBits() *
1796  * taking the same parameters as StretchBlt(). *
1797  * *
1798  * RETURNS : TRUE - if function succeeds. *
1799  * FALSE - otherwise. *
1800  * *
1801  ****************************************************************************/
1802 BOOL StretchDibBlt (
1803  HDC hdc,
1804  INT x,
1805  INT y,
1806  INT dx,
1807  INT dy,
1808  HANDLE hdib,
1809  INT x0,
1810  INT y0,
1811  INT dx0,
1812  INT dy0,
1813  LONG rop)
1814 
1815 {
1816  LPBITMAPINFOHEADER lpbi;
1817  LPSTR pBuf;
1818  BOOL f;
1819 
1820  if (!hdib)
1821  return PatBlt(hdc,x,y,dx,dy,rop);
1822 
1823  lpbi = (tagBITMAPINFOHEADER*)GlobalLock(hdib);
1824 
1825  if (!lpbi)
1826  return FALSE;
1827 
1828  pBuf = (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi);
1829 
1830  f = StretchDIBits ( hdc,
1831  x, y,
1832  dx, dy,
1833  x0, y0,
1834  dx0, dy0,
1835  pBuf, (LPBITMAPINFO)lpbi,
1836  DIB_RGB_COLORS,
1837  rop);
1838 
1839  GlobalUnlock(hdib);
1840  return f;
1841 }
1842 
1843 /****************************************************************************
1844  * *
1845  * FUNCTION : ReadDibBitmapInfo(int fh) *
1846  * *
1847  * PURPOSE : Will read a file in DIB format and return a global HANDLE *
1848  * to it's BITMAPINFO. This function will work with both *
1849  * "old" (BITMAPCOREHEADER) and "new" (BITMAPINFOHEADER) *
1850  * bitmap formats, but will always return a "new" BITMAPINFO *
1851  * *
1852  * RETURNS : A handle to the BITMAPINFO of the DIB in the file. *
1853  * *
1854  ****************************************************************************/
1855 HANDLE ReadDibBitmapInfo (INT fh)
1856 {
1857  DWORD off;
1858  HANDLE hbi = NULL;
1859  INT size;
1860  INT i;
1861  WORD nNumColors;
1862 
1863  RGBQUAD FAR *pRgb;
1864  BITMAPINFOHEADER bi;
1865  BITMAPCOREHEADER bc;
1866  LPBITMAPINFOHEADER lpbi;
1867  BITMAPFILEHEADER bf;
1868  DWORD dwWidth = 0;
1869  DWORD dwHeight = 0;
1870  WORD wPlanes, wBitCount;
1871 
1872  if (fh == -1)
1873  return NULL;
1874 #ifdef FIXDWORDALIGNMENT
1875  /* Reset file pointer and read file header */
1876  off = _llseek(fh, 0L, (UINT)SEEK_CUR);
1877  if ((SIZEOF_BITMAPFILEHEADER_PACKED) != _lread(fh, (LPSTR)&bf, (UINT)sizeof (SIZEOF_BITMAPFILEHEADER_PACKED)))
1878  return FALSE;
1879 #else
1880  ReadBitMapFileHeaderandConvertToDwordAlign(fh, &bf, &off);
1881  /* at this point we have read the file into bf*/
1882 #endif
1883 
1884 #if defined(_MAC)
1885  // swap the BITMAPFILEHEADER struct members around
1886  bf.bfType = SWAPWORD(bf.bfType);
1887  bf.bfSize = SWAPLONG(bf.bfSize);
1888  bf.bfReserved1 = SWAPWORD(bf.bfReserved1);
1889  bf.bfReserved2 = SWAPWORD(bf.bfReserved2);
1890  bf.bfOffBits = SWAPLONG(bf.bfOffBits);
1891 #endif
1892 
1893  /* Do we have a RC HEADER? */
1894  if (!ISDIB (bf.bfType)) {
1895  bf.bfOffBits = 0L;
1896  _llseek(fh, off, (UINT)SEEK_SET); /*seek back to beginning of file*/
1897  }
1898  if (sizeof (bi) != _lread(fh, (LPSTR)&bi, (UINT)sizeof(bi)))
1899  return FALSE;
1900 
1901 
1902  /* Check the nature (BITMAPINFO or BITMAPCORE) of the info. block
1903  * and extract the field information accordingly. If a BITMAPCOREHEADER,
1904  * transfer it's field information to a BITMAPINFOHEADER-style block
1905  */
1906  switch (size = (INT)(SWAPLONG(bi.biSize))){
1907  case sizeof (BITMAPINFOHEADER):
1908  #if defined(_MAC)
1909  bi.biSize = SWAPLONG(bi.biSize);
1910  bi.biWidth = SWAPLONG(bi.biWidth);
1911  bi.biHeight = SWAPLONG(bi.biHeight);
1912  bi.biPlanes = SWAPWORD(bi.biPlanes);
1913  bi.biBitCount = SWAPWORD(bi.biBitCount);
1914  bi.biCompression = SWAPLONG(bi.biCompression);
1915  bi.biSizeImage = SWAPLONG(bi.biSizeImage);
1916  bi.biXPelsPerMeter = SWAPLONG(bi.biXPelsPerMeter);
1917  bi.biYPelsPerMeter = SWAPLONG(bi.biYPelsPerMeter);
1918  bi.biClrUsed = SWAPLONG(bi.biClrUsed);
1919  bi.biClrImportant = SWAPLONG(bi.biClrImportant);
1920  #endif
1921  break;
1922 
1923  case sizeof (BITMAPCOREHEADER):
1924  bc = *(BITMAPCOREHEADER*)&bi;
1925  #if defined(_MAC)
1926  bc.bcSize = SWAPLONG(bc.bcSize);
1927  bc.bcWidth = SWAPWORD(bc.bcWidth);
1928  bc.bcHeight = SWAPWORD(bc.bcHeight);
1929  bc.bcPlanes = SWAPWORD(bc.bcPlanes);
1930  bc.bcBitCount = SWAPWORD(bc.bcBitCount);
1931  #endif
1932 
1933  nNumColors = DibNumColors (&bi);
1934 
1935  dwWidth = (DWORD)bc.bcWidth;
1936  dwHeight = (DWORD)bc.bcHeight;
1937  wPlanes = bc.bcPlanes;
1938  wBitCount = bc.bcBitCount;
1939 
1940  bi.biSize = sizeof(BITMAPINFOHEADER);
1941  bi.biWidth = dwWidth;
1942  bi.biHeight = dwHeight;
1943  bi.biPlanes = wPlanes;
1944  bi.biBitCount = wBitCount;
1945 
1946  bi.biCompression = BI_RGB;
1947  bi.biSizeImage = 0;
1948  bi.biXPelsPerMeter = 0;
1949  bi.biYPelsPerMeter = 0;
1950  bi.biClrUsed = nNumColors;
1951  bi.biClrImportant = nNumColors;
1952 
1953  _llseek(fh, (LONG)sizeof (BITMAPCOREHEADER) - sizeof (BITMAPINFOHEADER), (UINT)SEEK_CUR);
1954  break;
1955 
1956  default:
1957  /* Not a DIB! */
1958  return NULL;
1959  }
1960 
1961  nNumColors = DibNumColors (&bi);
1962 
1963  /* Fill in some default values if they are zero */
1964  if (bi.biSizeImage == 0){
1965  bi.biSizeImage = WIDTHBYTES ((DWORD)bi.biWidth * bi.biBitCount)
1966  * bi.biHeight;
1967  }
1968  if (bi.biClrUsed == 0)
1969  bi.biClrUsed = DibNumColors(&bi);
1970 
1971  /* Allocate for the BITMAPINFO structure and the color table. */
1972  hbi = GlobalAlloc (GHND, (LONG)bi.biSize + nNumColors * sizeof(RGBQUAD));
1973  if (!hbi)
1974  return NULL;
1975  lpbi = (tagBITMAPINFOHEADER*)GlobalLock (hbi);
1976  *lpbi = bi;
1977 
1978  /* Get a pointer to the color table */
1979  pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + bi.biSize);
1980  if (nNumColors){
1981  if (size == sizeof(BITMAPCOREHEADER)){
1982  /* Convert a old color table (3 byte RGBTRIPLEs) to a new
1983  * color table (4 byte RGBQUADs)
1984  */
1985  _lread(fh, (LPSTR)pRgb, (UINT)nNumColors * sizeof(RGBTRIPLE));
1986 
1987  for (i = nNumColors - 1; i >= 0; i--){
1988  RGBQUAD rgb;
1989 
1990  rgb.rgbRed = ((RGBTRIPLE FAR *)pRgb)[i].rgbtRed;
1991  rgb.rgbBlue = ((RGBTRIPLE FAR *)pRgb)[i].rgbtBlue;
1992  rgb.rgbGreen = ((RGBTRIPLE FAR *)pRgb)[i].rgbtGreen;
1993  rgb.rgbReserved = (BYTE)0;
1994 
1995  pRgb[i] = rgb;
1996  }
1997  }
1998  else
1999  _lread(fh, (LPSTR)pRgb, (UINT)nNumColors * sizeof(RGBQUAD));
2000  }
2001 
2002  if (bf.bfOffBits != 0L){
2003  _llseek(fh, off + bf.bfOffBits, (UINT)SEEK_SET);
2004  }
2005  GlobalUnlock(hbi);
2006  return hbi;
2007 }
2008 
2009 
2010 
2011 /****************************************************************************
2012  * *
2013  * FUNCTION : DibInfo(HANDLE hbi,LPBITMAPINFOHEADER lpbi) *
2014  * *
2015  * PURPOSE : Retrieves the DIB info associated with a CF_DIB *
2016  * format memory block. *
2017  * *
2018  * RETURNS : TRUE - if successful. *
2019  * FALSE - otherwise *
2020  * *
2021  ****************************************************************************/
2022 BOOL DibInfo (
2023  HANDLE hbi,
2024  LPBITMAPINFOHEADER lpbi)
2025 {
2026  if (hbi){
2027  *lpbi = *(LPBITMAPINFOHEADER)GlobalLock (hbi);
2028 
2029  /* fill in the default fields */
2030  if (lpbi->biSize != sizeof (BITMAPCOREHEADER)){
2031  if (lpbi->biSizeImage == 0L)
2032  lpbi->biSizeImage = WIDTHBYTES(lpbi->biWidth*lpbi->biBitCount) * lpbi->biHeight;
2033 
2034  if (lpbi->biClrUsed == 0L)
2035  lpbi->biClrUsed = DibNumColors (lpbi);
2036  }
2037  GlobalUnlock (hbi);
2038  return TRUE;
2039  }
2040  return FALSE;
2041 }
2042 
2043 
2044 /****************************************************************************
2045  * *
2046  * FUNCTION : CreateBIPalette(LPBITMAPINFOHEADER lpbi) *
2047  * *
2048  * PURPOSE : Given a Pointer to a BITMAPINFO struct will create a *
2049  * a GDI palette object from the color table. *
2050  * *
2051  * RETURNS : A handle to the palette. *
2052  * *
2053  ****************************************************************************/
2054 HPALETTE CreateBIPalette (LPBITMAPINFOHEADER lpbi)
2055 {
2056  LOGPALETTE *pPal;
2057  HPALETTE hpal = NULL;
2058  WORD nNumColors;
2059  BYTE red;
2060  BYTE green;
2061  BYTE blue;
2062  WORD i;
2063  RGBQUAD FAR *pRgb;
2064 
2065  if (!lpbi)
2066  return NULL;
2067 
2068  if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
2069  return NULL;
2070 
2071  /* Get a pointer to the color table and the number of colors in it */
2072  pRgb = (RGBQUAD FAR *)((LPSTR)lpbi + (WORD)lpbi->biSize);
2073  nNumColors = DibNumColors(lpbi);
2074 
2075  if (nNumColors){
2076  /* Allocate for the logical palette structure */
2077  pPal = (LOGPALETTE*)LocalAlloc(LPTR,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
2078  if (!pPal)
2079  return NULL;
2080 
2081  pPal->palNumEntries = nNumColors;
2082  pPal->palVersion = PALVERSION;
2083 
2084  /* Fill in the palette entries from the DIB color table and
2085  * create a logical color palette.
2086  */
2087  for (i = 0; i < nNumColors; i++){
2088  pPal->palPalEntry[i].peRed = pRgb[i].rgbRed;
2089  pPal->palPalEntry[i].peGreen = pRgb[i].rgbGreen;
2090  pPal->palPalEntry[i].peBlue = pRgb[i].rgbBlue;
2091  pPal->palPalEntry[i].peFlags = (BYTE)0;
2092  }
2093  hpal = CreatePalette(pPal);
2094  LocalFree((HANDLE)pPal);
2095  }
2096  else if (lpbi->biBitCount >= 24){
2097  /* A 24 bitcount DIB has no color table entries so, set the number of
2098  * to the maximum value (256).
2099  */
2100  nNumColors = MAXPALETTE;
2101  pPal = (LOGPALETTE*)LocalAlloc(LPTR,sizeof(LOGPALETTE) + nNumColors * sizeof(PALETTEENTRY));
2102  if (!pPal)
2103  return NULL;
2104 
2105  pPal->palNumEntries = nNumColors;
2106  pPal->palVersion = PALVERSION;
2107 
2108  red = green = blue = 0;
2109 
2110  /* Generate 256 (= 8*8*4) RGB combinations to fill the palette
2111  * entries.
2112  */
2113  for (i = 0; i < pPal->palNumEntries; i++){
2114  pPal->palPalEntry[i].peRed = red;
2115  pPal->palPalEntry[i].peGreen = green;
2116  pPal->palPalEntry[i].peBlue = blue;
2117  pPal->palPalEntry[i].peFlags = (BYTE)0;
2118 
2119  if (!(red += 32))
2120  if (!(green += 32))
2121  blue += 64;
2122  }
2123  hpal = CreatePalette(pPal);
2124  LocalFree((HANDLE)pPal);
2125  }
2126  return hpal;
2127 }
2128 
2129 /****************************************************************************
2130  * *
2131  * FUNCTION : CreateDibPalette(HANDLE hbi) *
2132  * *
2133  * PURPOSE : Given a Global HANDLE to a BITMAPINFO Struct *
2134  * will create a GDI palette object from the color table. *
2135  * (BITMAPINFOHEADER format DIBs only) *
2136  * *
2137  * RETURNS : A handle to the palette. *
2138  * *
2139  ****************************************************************************/
2140 HPALETTE CreateDibPalette (HANDLE hbi)
2141 {
2142  HPALETTE hpal;
2143 
2144  if (!hbi)
2145  return NULL;
2146  hpal = CreateBIPalette((LPBITMAPINFOHEADER)GlobalLock(hbi));
2147  GlobalUnlock(hbi);
2148  return hpal;
2149 }
2150 
2151 /****************************************************************************
2152  * *
2153  * FUNCTION :OpenDIB(LPSTR szFile) *
2154  * *
2155  * PURPOSE :Open a DIB file and create a MEMORY DIB, a memory handle *
2156  * containing BITMAPINFO, palette data and the bits. *
2157  * *
2158  * RETURNS :A handle to the DIB. *
2159  * *
2160  ****************************************************************************/
2161 HANDLE OpenDIB (LPSTR szFile)
2162 {
2163  HFILE fh;
2164  BITMAPINFOHEADER bi;
2165  LPBITMAPINFOHEADER lpbi;
2166  DWORD dwLen = 0;
2167  DWORD dwBits;
2168  HANDLE hdib;
2169  HANDLE h;
2170  OFSTRUCT of;
2171 
2172  /* Open the file and read the DIB information */
2173  fh = OpenFile(szFile, &of, (UINT)OF_READ);
2174  if (fh == -1)
2175  return NULL;
2176 
2177  hdib = ReadDibBitmapInfo(fh);
2178  if (!hdib)
2179  return NULL;
2180  DibInfo(hdib,&bi);
2181 
2182  /* Calculate the memory needed to hold the DIB */
2183  dwBits = bi.biSizeImage;
2184  dwLen = bi.biSize + (DWORD)PaletteSize (&bi) + dwBits;
2185 
2186  /* Try to increase the size of the bitmap info. buffer to hold the DIB */
2187  h = GlobalReAlloc(hdib, dwLen, GHND);
2188  if (!h){
2189  GlobalFree(hdib);
2190  hdib = NULL;
2191  }
2192  else
2193  hdib = h;
2194 
2195  /* Read in the bits */
2196  if (hdib){
2197 
2198  lpbi = (tagBITMAPINFOHEADER*)GlobalLock(hdib);
2199  lread(fh, (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize(lpbi), dwBits);
2200  GlobalUnlock(hdib);
2201  }
2202  _lclose(fh);
2203 
2204  return hdib;
2205 }
2206 
2207 /****************************************************************************
2208  * *
2209  * FUNCTION : PaletteSize(VOID FAR * pv) *
2210  * *
2211  * PURPOSE : Calculates the palette size in bytes. If the info. block *
2212  * is of the BITMAPCOREHEADER type, the number of colors is *
2213  * multiplied by 3 to give the palette size, otherwise the *
2214  * number of colors is multiplied by 4. *
2215  * *
2216  * RETURNS : Palette size in number of bytes. *
2217  * *
2218  ****************************************************************************/
2219 WORD PaletteSize (VOID FAR * pv)
2220 {
2221  LPBITMAPINFOHEADER lpbi;
2222  WORD NumColors;
2223 
2224  lpbi = (LPBITMAPINFOHEADER)pv;
2225  NumColors = DibNumColors(lpbi);
2226 
2227  if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
2228  return (WORD)(NumColors * sizeof(RGBTRIPLE));
2229  else
2230  return (WORD)(NumColors * sizeof(RGBQUAD));
2231 }
2232 
2233 /****************************************************************************
2234  * *
2235  * FUNCTION : DibNumColors(VOID FAR * pv) *
2236  * *
2237  * PURPOSE : Determines the number of colors in the DIB by looking at *
2238  * the BitCount filed in the info block. *
2239  * *
2240  * RETURNS : The number of colors in the DIB. *
2241  * *
2242  ****************************************************************************/
2243 WORD DibNumColors (VOID FAR * pv)
2244 {
2245  INT bits;
2246  LPBITMAPINFOHEADER lpbi;
2247  LPBITMAPCOREHEADER lpbc;
2248 
2249  lpbi = ((LPBITMAPINFOHEADER)pv);
2250  lpbc = ((LPBITMAPCOREHEADER)pv);
2251 
2252  /* With the BITMAPINFO format headers, the size of the palette
2253  * is in biClrUsed, whereas in the BITMAPCORE - style headers, it
2254  * is dependent on the bits per pixel ( = 2 raised to the power of
2255  * bits/pixel).
2256  */
2257  if (lpbi->biSize != sizeof(BITMAPCOREHEADER)){
2258  if (lpbi->biClrUsed != 0)
2259  return (WORD)lpbi->biClrUsed;
2260  bits = lpbi->biBitCount;
2261  }
2262  else
2263  bits = lpbc->bcBitCount;
2264 
2265  switch (bits){
2266  case 1:
2267  return 2;
2268  case 4:
2269  return 16;
2270  case 8:
2271  return 256;
2272  default:
2273  /* A 24 bitcount DIB has no color table */
2274  return 0;
2275  }
2276 }
2277 
2278 
2279 /****************************************************************************
2280  * *
2281  * FUNCTION : ReadBitMapFileHeaderandConvertToDwordAlign(HFILE fh, LPBITMAPFILEHEADER pbf)
2282  * *
2283  * PURPOSE : read file header (which is packed) and convert into unpacked BITMAPFILEHEADER strucutre
2284  * *
2285  * RETURNS : VOID
2286  * *
2287  ****************************************************************************/
2288 
2289 VOID ReadBitMapFileHeaderandConvertToDwordAlign(HFILE fh, LPBITMAPFILEHEADER pbf, LPDWORD lpdwoff)
2290 {
2291  DWORD off;
2292 
2293  off = _llseek(fh, 0L, (UINT) SEEK_CUR);
2294  *lpdwoff = off;
2295 
2296 /* BITMAPFILEHEADER STRUCUTURE is as follows
2297  * BITMAPFILEHEADER
2298  * WORD bfType
2299  > .... < add WORD if packed here!
2300  * DWORD bfSize
2301  * WORD bfReserved1
2302  * WORD bfReserved2
2303  * DWORD bfOffBits
2304  * This is the packed format, unpacked adds a WORD after bfType
2305  */
2306 
2307  /* read in bfType*/
2308  _lread(fh, (LPSTR) &pbf->bfType, sizeof(WORD));
2309  /* read in last 3 dwords*/
2310  _lread(fh, (LPSTR) &pbf->bfSize, sizeof(DWORD) * 3);
2311 
2312 }
2313 
2314 
2315 /****************************************************************************
2316  * *
2317  * FUNCTION : ErrMsg (PSTR sz,...) *
2318  * *
2319  * PURPOSE : Opens a Message box with a error message in it.The user can*
2320  * select the OK button to continue *
2321  * *
2322  * RETURNS : FALSE to indicate an error has occured. *
2323  * *
2324  ****************************************************************************/
2325 INT ErrMsg (PSTR sz,...)
2326 {
2327  CHAR ach[512];
2328 
2329  va_list args;
2330 
2331  va_start(args, sz);
2332 
2333  wvsprintf (ach, sz, args); /* Format the string */
2334  MessageBox (NULL, ach, NULL, MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
2335  return FALSE;
2336 }
2337 
2338 /****************************************************************************
2339  * *
2340  * FUNCTION : DrawBitmap(HDC hdc, int x, int y, HBITMAP hbm, DWORD rop) *
2341  * *
2342  * PURPOSE : Draws bitmap <hbm> at the specifed position in DC <hdc> *
2343  * *
2344  * RETURNS : Return value of BitBlt() *
2345  * *
2346  ****************************************************************************/
2347 BOOL DrawBitmap (
2348  HDC hdc,
2349  INT x,
2350  INT y,
2351  HBITMAP hbm,
2352  DWORD rop)
2353 {
2354  HDC hdcBits;
2355  BITMAP bm;
2356 // HPALETTE hpalT;
2357  BOOL f;
2358 
2359  if (!hdc || !hbm)
2360  return FALSE;
2361 
2362  // Made this code a little more robust
2363  // by checking the results of a few calls.
2364  // memory, esp on the mac, can get sucked
2365  // up really fast and make these fail
2366  // 2-9-94 Garth Brown
2367  //
2368  if(hdcBits = CreateCompatibleDC(hdc))
2369  {
2370  if(GetObject(hbm,sizeof(BITMAP),(LPSTR)&bm) != 0)
2371  {
2372  HGDIOBJ hObj;
2373 
2374  hObj = SelectObject(hdcBits,hbm);
2375  if ((hObj != NULL) && (hObj != (HGDIOBJ)GDI_ERROR))
2376  {
2377  f = BitBlt(hdc,x, y,bm.bmWidth,bm.bmHeight,hdcBits,0,0,rop);
2378  }
2379  else
2380  {
2381  // most likely to fail, so we'll put a message box here
2382  //
2383  MessageBox(NULL, "Select Object failed: out of memory?",
2384  "Error Selecting Bitmap!", MB_OK);
2385  return(FALSE);
2386  }
2387  }
2388  DeleteDC(hdcBits);
2389  }
2390 
2391  return f;
2392  UNREFERENCED_PARAMETER(y);
2393  UNREFERENCED_PARAMETER(x);
2394 }
2395 
2396 
2397 /****************************************************************************
2398  * *
2399  * FUNCTION : DrawBitmap(HDC hdc, int x, int y, int width, int height, HBITMAP hbm, DWORD rop) *
2400  * *
2401  * PURPOSE : Draws bitmap <hbm> at the specifed position in DC <hdc> *
2402  * Andy's copy of DrawBitmap - scales or centres as needed *
2403  * *
2404  * RETURNS : Return value of BitBlt() *
2405  * *
2406  ****************************************************************************/
2407 BOOL DrawBitmapScaled (
2408  HDC hdc,
2409  INT x,
2410  INT y,
2411  INT inWidth,
2412  INT inHeight,
2413  HBITMAP hbm,
2414  DWORD rop)
2415 {
2416  HDC hdcBits;
2417  BITMAP bm;
2418 // HPALETTE hpalT;
2419  BOOL f;
2420 
2421  if (!hdc || !hbm)
2422  return FALSE;
2423 
2424  // Made this code a little more robust
2425  // by checking the results of a few calls.
2426  // memory, esp on the mac, can get sucked
2427  // up really fast and make these fail
2428  // 2-9-94 Garth Brown
2429  //
2430  if(hdcBits = CreateCompatibleDC(hdc))
2431  {
2432  if(GetObject(hbm,sizeof(BITMAP),(LPSTR)&bm) != 0)
2433  {
2434  HGDIOBJ hObj;
2435 
2436  const int actualWidth = bm.bmWidth;
2437  const int actualHeight = bm.bmHeight;
2438  int drawHeight = actualHeight;
2439  int drawWidth = actualWidth;
2440  bool changedSize = false;
2441 // check scaling according to widths
2442 // calling logic in oofRepPictBlock and oofRepPictBand sets height
2443 // from actual height
2444  if (actualWidth>inWidth) { // scale down
2445  drawWidth = inWidth;
2446  drawHeight = actualHeight * inWidth/actualWidth;
2447  changedSize = true;
2448  }
2449  else if (actualWidth<inWidth) { // centre smaller picture horizontally, leave at top vertically
2450  x += (inWidth - actualWidth)/2;
2451  }
2452  hObj = SelectObject(hdcBits,hbm);
2453  if ((hObj != NULL) && (hObj != (HGDIOBJ)GDI_ERROR))
2454  {
2455  if (changedSize)
2456  f = StretchBlt(hdc,x, y, drawWidth, drawHeight, hdcBits,0,0,actualWidth, actualHeight, rop);
2457  else
2458  f = BitBlt(hdc,x, y, drawWidth, drawHeight, hdcBits,0,0,rop);
2459  }
2460  else
2461  {
2462  // most likely to fail, so we'll put a message box here
2463  //
2464  MessageBox(NULL, "Select Object failed: out of memory?",
2465  "Error Selecting Bitmap!", MB_OK);
2466  return(FALSE);
2467  }
2468  }
2469  DeleteDC(hdcBits);
2470  }
2471 
2472  return f;
2473 }
2474 
2475 
2476 /****************************************************************************
2477  * *
2478  * FUNCTION : BitmapFromDib(HANDLE hdib, HPALETTE hpal) *
2479  * *
2480  * PURPOSE : Will create a DDB (Device Dependent Bitmap) given a global *
2481  * handle to a memory block in CF_DIB format *
2482  * *
2483  * RETURNS : A handle to the DDB. *
2484  * *
2485  ****************************************************************************/
2486 HBITMAP BitmapFromDib (
2487  HANDLE hdib,
2488  HPALETTE hpal)
2489 {
2490  LPBITMAPINFOHEADER lpbi;
2491  HPALETTE hpalT;
2492  HDC hdc;
2493  HBITMAP hbm;
2494 
2495 // StartWait();
2496 
2497  if (!hdib)
2498  return NULL;
2499 
2500  lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);
2501 
2502  if (!lpbi)
2503  return NULL;
2504 
2505  hdc = GetDC(NULL);
2506 
2507  if (hpal){
2508  hpalT = SelectPalette(hdc,hpal,FALSE);
2509  RealizePalette(hdc); // GDI Bug...????
2510  }
2511 
2512  hbm = CreateDIBitmap(hdc,
2513  (LPBITMAPINFOHEADER)lpbi,
2514  (LONG)CBM_INIT,
2515  (LPSTR)lpbi + lpbi->biSize + PaletteSize(lpbi),
2516  (LPBITMAPINFO)lpbi,
2517  DIB_RGB_COLORS );
2518 
2519  if (hpal)
2520  SelectPalette(hdc,hpalT,FALSE);
2521 
2522  ReleaseDC(NULL,hdc);
2523  GlobalUnlock(hdib);
2524 
2525 // EndWait();
2526 
2527  return hbm;
2528 }
2529 
2530 
2531 #endif // _Windows
unsigned long height()
Definition: oofdraw.cpp:1241
void loadSecondaryJPEG(const oofFileRef &)
Definition: oofdraw.cpp:1487
typedef LONG(ctDECL *ctComparativeKeySearch)(COUNT
static bool invariant()
Definition: oofdraw.cpp:348
oofPict(const oofFileRef &)
Definition: oofdraw.cpp:1179
Macintosh structure for a rectangle.
void SkipWhiteForward(const char *inValue, unsigned long &ioWordStart, unsigned long &ioCharsLeft) const
Definition: oofdraw.cpp:689
unsigned char BYTE
Definition: oofrpRTF.cpp:24
oofString describe() const
Definition: oofdraw.cpp:1262
Definition: oofync.h:22
~oofPict()
Definition: oofdraw.cpp:1216
void StoreLineLength(unsigned long inLineStart)
Definition: oofdraw.cpp:676
virtual void describe(std::ostream &) const
Definition: oofdraw.cpp:987
const unsigned long * GetLineStarts() const
Definition: oofdraw.h:348
const unsigned long * GetLineLengths(unsigned short index) const
Definition: oofdraw.cpp:1103
#define _Windows
This build is on Windows.
Definition: doxyoof.h:440
oofPict * clone() const
Definition: oofdraw.cpp:1234
void convertNumber(int, const char *printfMask=0, bool appendIt=false)
Definition: oofstr.cpp:882
virtual void CalculateWrapping(const char *inValue, unsigned long inItemSize, unsigned long inColWidth, bool inTruncWords=true)
Produce two arrays of line start (offset of character from start of string) and line length (pixels)...
Definition: oofdraw.cpp:765
unsigned long TruncateTrailingWord(const char *inValue, unsigned long inEndWord, unsigned long &outNextWordStart) const
Definition: oofdraw.cpp:1018
virtual void CalculateWrapping(unsigned short index, unsigned short inColWidth, bool inTruncWords=true)
Definition: oofdraw.cpp:1119
unsigned long length() const
Primary test: oofStringTest::emptyStringByNullInitIsLenZero()
Definition: oofstr.h:447
const unsigned long * GetLineLengths() const
Definition: oofdraw.h:355
Portable way to refer to files.
Definition: ooffiles.h:66
Implement Windows specific OOFILE DIB COPYRIGHT 2002 A.D.
Portable highly capable string class.
Definition: oofstr.h:101
static bool setFontSize(int textSize=-1)
Definition: oofdraw.cpp:293
Store a shared chunk of binary info with reference count to avoid copying.
Definition: oofStruct.h:29
virtual ~OOF_mixPictOwner()
Definition: oofdraw.cpp:1517
void StoreLineStart(unsigned long inLineStart)
Definition: oofdraw.cpp:651
Cross-platform sizer which wraps to multiple rows.
Definition: oofdraw.h:82
void initSizers(unsigned short numItems)
Definition: oofdraw.cpp:1074
OOF_GWorldOwner & operator=(GWorldPtr adoptedGWorld)
Definition: oofdraw.cpp:1558
static int calcCharHeight(int textSize=-1)
Definition: oofdraw.cpp:378
static PicHandle readPict(const oofFileRef &)
Definition: oofdraw.cpp:1348
void draw(int x, int y, int right, int bottom, bool onPrinter=false)
Definition: oofdraw.cpp:1370
oofString path() const
#define _Macintosh
This build is on Macintosh.
Definition: doxyoof.h:433
virtual ~oofTextSizer()
Definition: oofdraw.cpp:638
void readBinary(oofSharedBLOB *) const
void decRefs()
Definition: oof1.cpp:3212
unsigned short GetNumRows() const
Definition: oofdraw.h:360
unsigned short GetNumRows(unsigned short index) const
Definition: oofdraw.cpp:1111
void incRefs()
Definition: oof1.h:2677
const unsigned long * GetLineStarts(unsigned short index) const
Definition: oofdraw.cpp:1095
const FSSpec & spec() const
Definition: ooffiles.h:78
Mixin for classes keeping an oofPict member.
Definition: oofdraw.h:269
oofString & text(unsigned short index) const
Definition: oofdraw.cpp:1088
unsigned long width()
Definition: oofdraw.cpp:1251
const GWorldPtr gWorld()
Definition: oofdraw.h:171
Reference-counted wrapper for a GWorld.
Definition: oofdraw.h:164
bool isValid() const
OOF_mixPictOwner(oofPict *adoptedPict)
Definition: oofdraw.cpp:1502
Cross-platform picture representation can load from file or resource and draw.
Definition: oofdraw.h:201