graphics.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:51k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * graphics.cxx
  3.  *
  4.  * Graphics, Canvas and drawing classes.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: graphics.cxx,v $
  30.  * Revision 1.38  1999/09/05 14:39:22  robertj
  31.  * GNU 2.95 compatibility
  32.  *
  33.  * Revision 1.37  1998/10/16 11:08:15  robertj
  34.  * GNU compatibility.
  35.  *
  36.  * Revision 1.36  1998/09/23 06:29:38  robertj
  37.  * Added open source copyright license.
  38.  *
  39.  * Revision 1.35  1998/09/22 15:06:38  robertj
  40.  * Added delayed HDC creation in PDrawCanvas.
  41.  *
  42.  * Revision 1.34  1998/03/20 03:14:11  robertj
  43.  * Added function to get physical bounds of canvas. Allows to scale drawing.
  44.  *
  45.  * Revision 1.33  1997/04/27 05:50:21  robertj
  46.  * DLL support.
  47.  *
  48.  * Revision 1.32  1996/11/04 03:39:34  robertj
  49.  * Fixed warning about uninitialised variable.
  50.  *
  51.  * Revision 1.31  1996/07/15 10:34:21  robertj
  52.  * Fixed uninitialised variable.
  53.  * Changed endian classes to be memory mapped.
  54.  *
  55.  * Revision 1.30  1996/06/28 13:17:37  robertj
  56.  * Removed integer size mismatch warnings
  57.  *
  58.  * Revision 1.29  1996/06/17 11:42:16  robertj
  59.  * Creation of a default palette for 24 bit images.
  60.  *
  61.  * Revision 1.28  1996/01/28 02:52:02  robertj
  62.  * Added assert into all Compare functions to assure comparison between compatible objects.
  63.  *
  64.  * Revision 1.27  1995/12/10 11:38:21  robertj
  65.  * Removed eatwhite() as not in GNU library.
  66.  * Fixed automatic operator translation incompatibility amongst compilers.
  67.  *
  68.  * Revision 1.26  1995/11/21 11:52:35  robertj
  69.  * Improved streams compatibility.
  70.  * Added 16 bit windows support for bitmap reading.
  71.  *
  72.  * Revision 1.24  1995/10/14 15:09:57  robertj
  73.  * Changed return values to references for efficency.
  74.  *
  75.  * Revision 1.23  1995/08/12 22:33:42  robertj
  76.  * Changed DrawBevelledRect() so does not change background colour.
  77.  *
  78.  * Revision 1.22  1995/04/25 11:29:20  robertj
  79.  * Fixed Borland compiler warnings.
  80.  *
  81.  * Revision 1.21  1995/02/22 10:50:36  robertj
  82.  * Changes required for compiling release (optimised) version.
  83.  *
  84.  * Revision 1.20  1995/01/27  11:13:43  robertj
  85.  * Added pattern origin.
  86.  *
  87.  * Revision 1.19  1995/01/21  05:14:31  robertj
  88.  * Added origin changing function, simpler than setting rectangles.
  89.  * Fixed rounding error for negative numbers in coordinate system conversions.
  90.  *
  91.  * Revision 1.18  1995/01/06  10:43:59  robertj
  92.  * Changed PRealFont usage from pointer to reference.
  93.  *
  94.  * Revision 1.17  1994/12/14  11:17:17  robertj
  95.  * Changed PDIMENSION to be unsigned causing untold number of changes.
  96.  *
  97.  * Revision 1.16  1994/12/12  10:07:15  robertj
  98.  * Made depth member of PPixels and removed virtual function.
  99.  *
  100.  * Revision 1.15  1994/12/05  11:34:25  robertj
  101.  * Major rewrite of images, pictures and pixmaps.
  102.  * Renamed PPict, PPixels and PImage to make sure all uses are found.
  103.  *
  104.  * Revision 1.14  1994/11/01  11:57:47  robertj
  105.  * Removed lots of signed/unsigned mismatch warnings.
  106.  *
  107.  * Revision 1.13  1994/10/30  11:51:29  robertj
  108.  * Added ability to change interactor foreground colour on a per interactor basis.
  109.  *
  110.  * Revision 1.12  1994/10/23  03:45:22  robertj
  111.  * Added multiply and divide operators for points and dims.
  112.  * Changed PPixels to have subclasses for each pixel size and be fully polymorhic.
  113.  *
  114.  * Revision 1.11  1994/08/21  23:43:02  robertj
  115.  * Optimisation of DrawString() for transparent background.
  116.  *
  117.  * Revision 1.10  1994/08/01  03:41:24  robertj
  118.  * Use of PNEW instead of new for heap debugging. Need undef for Unix end.
  119.  *
  120.  * Revision 1.9  1994/07/27  05:58:07  robertj
  121.  * Synchronisation.
  122.  *
  123.  * Revision 1.8  1994/06/25  11:55:15  robertj
  124.  * Unix version synchronisation.
  125.  *
  126.  * Revision 1.7  1994/04/20  12:17:44  robertj
  127.  * assert changes
  128.  *
  129.  * Revision 1.6  1994/03/07  07:47:00  robertj
  130.  * Major upgrade
  131.  *
  132.  * Revision 1.5  1994/01/03  04:42:23  robertj
  133.  * Mass changes to common container classes and interactors etc etc etc.
  134.  *
  135.  * Revision 1.4  1993/12/31  06:53:02  robertj
  136.  * Made inlines optional for debugging purposes.
  137.  *
  138.  * Revision 1.3  1993/12/15  23:41:27  robertj
  139.  * Removed triadic conditional expressions as GCC can't do it.
  140.  *
  141.  * Revision 1.2  1993/12/04  05:23:25  robertj
  142.  * More implementation
  143.  *
  144.  * Revision 1.1  1993/11/20  17:26:28  robertj
  145.  * Initial revision
  146.  */
  147. #include <pwlib.h>
  148. #include <ctype.h>
  149. #define new PNEW
  150. ///////////////////////////////////////////////////////////////////////////////
  151. // PDim
  152. #if defined(_PDIM)
  153. PObject * PDim::Clone() const
  154. {
  155.   return new PDim(width, height);
  156. }
  157. PObject::Comparison PDim::Compare(const PObject & obj) const
  158. {
  159.   PAssert(obj.IsDescendant(PDim::Class()), PInvalidCast);
  160.   const PDim & other = (const PDim &)obj;
  161.   if (height == other.height && width == other.width)
  162.     return EqualTo;
  163.   else
  164.     return width*height < other.width*other.height ? LessThan : GreaterThan;
  165. }
  166. PDim PDim::operator+(const PDim & dim) const
  167. {
  168.   return PDim(width+dim.width, height+dim.height);
  169. }
  170. PDim PDim::operator+(const PPoint & pt) const
  171. {
  172.   return PDim(width+pt.X(), height+pt.Y());
  173. }
  174. PDim & PDim::operator+=(const PDim & dim)
  175. {
  176.   width += dim.width;
  177.   height += dim.height;
  178.   return *this;
  179. }
  180. PDim & PDim::operator+=(const PPoint & pt)
  181. {
  182.   width += (PDIMENSION)pt.X();
  183.   height += (PDIMENSION)pt.Y();
  184.   return *this;
  185. }
  186. PDim PDim::operator-(const PDim & dim) const
  187. {
  188.   return PDim(width-dim.width, height-dim.height);
  189. }
  190. PDim & PDim::operator-=(const PDim & dim)
  191. {
  192.   width -= dim.width;
  193.   height -= dim.height;
  194.   return *this;
  195. }
  196. PDim & PDim::operator-=(const PPoint & pt)
  197. {
  198.   width -= (PDIMENSION)pt.X();
  199.   height -= (PDIMENSION)pt.Y();
  200.   return *this;
  201. }
  202. PDim PDim::operator*(PDIMENSION scale) const
  203. {
  204.   return PDim(width*scale, height*scale);
  205. }
  206. PDim & PDim::operator*=(PDIMENSION scale)
  207. {
  208.   width *= scale;
  209.   height *= scale;
  210.   return *this;
  211. }
  212. PDim PDim::operator/(PDIMENSION scale) const
  213. {
  214.   return PDim(width/scale, height/scale);
  215. }
  216. PDim & PDim::operator/=(PDIMENSION scale)
  217. {
  218.   width /= scale;
  219.   height /= scale;
  220.   return *this;
  221. }
  222. #endif
  223. ///////////////////////////////////////////////////////////////////////////////
  224. // PPoint
  225. #if defined(_PPOINT)
  226. PObject * PPoint::Clone() const
  227. {
  228.   return new PPoint(*this);
  229. }
  230. PObject::Comparison PPoint::Compare(const PObject & obj) const
  231. {
  232.   PAssert(obj.IsDescendant(PPoint::Class()), PInvalidCast);
  233.   const PPoint & other = (const PPoint &)obj;
  234.   if (X() == other.X() && Y() == other.Y())
  235.     return EqualTo;
  236.   return X()+Y() < other.X()+other.Y() ? LessThan : GreaterThan;
  237. }
  238. PPoint PPoint::operator+(const PPoint & pt) const
  239. {
  240.   return PPoint(X()+pt.X(), Y()+pt.Y());
  241. }
  242. PPoint PPoint::operator+(const PDim & dim) const
  243. {
  244.   return PPoint(X()+dim.Width(), Y()+dim.Height());
  245. }
  246. PPoint PPoint::operator-(const PPoint & pt) const
  247. {
  248.   return PPoint(X()-pt.X(), Y()-pt.Y());
  249. }
  250. PPoint PPoint::operator-(const PDim & dim) const
  251. {
  252.   return PPoint(X()-dim.Width(), Y()-dim.Height());
  253. }
  254. PPoint PPoint::operator*(const PPoint & pt) const
  255. {
  256.   return PPoint(X()*pt.X(), Y()*pt.Y());
  257. }
  258. PPoint PPoint::operator*(const PDim & dim) const
  259. {
  260.   return PPoint(X()*dim.Width(), Y()*dim.Height());
  261. }
  262. PPoint PPoint::operator*(PORDINATE scale) const
  263. {
  264.   return PPoint(X()*scale, Y()*scale);
  265. }
  266. PPoint PPoint::operator/(const PPoint & pt) const
  267. {
  268.   return PPoint(X()/pt.X(), Y()/pt.Y());
  269. }
  270. PPoint PPoint::operator/(const PDim & dim) const
  271. {
  272.   return PPoint(X()/dim.Width(), Y()/dim.Height());
  273. }
  274. PPoint PPoint::operator/(PORDINATE scale) const
  275. {
  276.   return PPoint(X()/scale, Y()/scale);
  277. }
  278. #endif
  279. ///////////////////////////////////////////////////////////////////////////////
  280. // PRect
  281. #if defined(_PRECT)
  282. PObject * PRect::Clone() const
  283. {
  284.   return new PRect(*this);
  285. }
  286. PPoint PRect::Centre() const
  287. {
  288.   return PPoint(X()+Width()/2, Y()+Height()/2);
  289. }
  290. void PRect::SetOrigin(PORDINATE nx, PORDINATE ny)
  291. {
  292.   SetX(nx);
  293.   SetY(ny);
  294. }
  295. void PRect::SetOrigin(const PPoint & org)
  296. {
  297.   SetX(org.X());
  298.   SetY(org.Y());
  299. }
  300. void PRect::SetCorner(PORDINATE nx, PORDINATE ny)
  301. {
  302.   SetRight(nx);
  303.   SetBottom(ny);
  304. }
  305. void PRect::SetCorner(const PPoint & cnr)
  306. {
  307.   SetRight(cnr.X());
  308.   SetBottom(cnr.Y());
  309. }
  310. void PRect::SetDimensions(PDIMENSION dx, PDIMENSION dy)
  311. {
  312.   SetWidth(dx);
  313.   SetHeight(dy);
  314. }
  315. void PRect::SetDimensions(const PDim & dim)
  316. {
  317.   SetWidth(dim.Width());
  318.   SetHeight(dim.Height());
  319. }
  320. #endif
  321. ///////////////////////////////////////////////////////////////////////////////
  322. // PPixels
  323. PPixelImage::PPixelImage(PDIMENSION dx, PDIMENSION dy, BYTE depth)
  324. {
  325.   switch (depth) {
  326.     case 32 :
  327.       operator=(PPixelImage(new PPixels32(dx, dy)));
  328.       break;
  329.     case 24 :
  330.       operator=(PPixelImage(new PPixels24(dx, dy)));
  331.       break;
  332.     case 8 :
  333.       operator=(PPixelImage(new PPixels8(dx, dy)));
  334.       break;
  335.     case 4 :
  336.       operator=(PPixelImage(new PPixels4(dx, dy)));
  337.       break;
  338.     case 2 :
  339.       operator=(PPixelImage(new PPixels2(dx, dy)));
  340.       break;
  341.     case 1 :
  342.       operator=(PPixelImage(new PPixels1(dx, dy)));
  343.       break;
  344.     default:
  345.       PAssertAlways(PUnsupportedFeature);
  346.   }
  347. }
  348. struct P_BITMAPINFOHEADER {
  349.   P_BITMAPINFOHEADER(istream & s)
  350.     { s >> biWidth >> biHeight >> biPlanes >> biBitCount
  351.         >> biCompression >> biSizeImage >> biXPelsPerMeter
  352.         >> biYPelsPerMeter >> biClrUsed >> biClrImportant;
  353.     }
  354.   PUInt32l biWidth;
  355.   PUInt32l biHeight;
  356.   PUInt16l biPlanes;
  357.   PUInt16l biBitCount;
  358.   PUInt32l biCompression;
  359.   PUInt32l biSizeImage;
  360.   PUInt32l biXPelsPerMeter;
  361.   PUInt32l biYPelsPerMeter;
  362.   PUInt32l biClrUsed;
  363.   PUInt32l biClrImportant;
  364. };
  365. struct P_RGBQUAD {
  366.   P_RGBQUAD(istream & s)
  367.     { s >> rgbBlue >> rgbGreen >> rgbRed >> rgbReserved; }
  368.   operator PColour() const { return PColour(rgbRed, rgbGreen, rgbBlue); }
  369.   PUInt8 rgbBlue;
  370.   PUInt8 rgbGreen;
  371.   PUInt8 rgbRed;
  372.   PUInt8 rgbReserved;
  373. };
  374. struct P_BITMAPCOREHEADER {
  375.   P_BITMAPCOREHEADER(istream & s)
  376.     { s >> bcWidth >> bcHeight >> bcPlanes >> bcBitCount; }
  377.   PUInt16l bcWidth;
  378.   PUInt16l bcHeight;
  379.   PUInt16l bcPlanes;
  380.   PUInt16l bcBitCount;
  381. };
  382. struct P_RGBTRIPLE {
  383.   P_RGBTRIPLE(istream & s)
  384.     { s >> rgbtBlue >> rgbtGreen >> rgbtRed; }
  385.   operator PColour() const { return PColour(rgbtRed, rgbtGreen, rgbtBlue); }
  386.   PUInt8 rgbtBlue;
  387.   PUInt8 rgbtGreen;
  388.   PUInt8 rgbtRed;
  389. };
  390. static void ReadBMP(istream & stream, PPixelImage & image)
  391. {
  392.   stream.ignore(12); // Skip rest of BITMAPFILEHEADER structure
  393.   PUInt32l hdrsize;  // Read size of header for bitmap
  394.   stream >> hdrsize;
  395.   PPalette palette;
  396.   DWORD width, height, imageSize;
  397.   WORD bitCount;
  398.   PINDEX colourCount;
  399.   switch ((DWORD)hdrsize) {
  400.     case 40 : {
  401.       P_BITMAPINFOHEADER bmih(stream);
  402.       if (!stream.good())
  403.         return;
  404.       width = bmih.biWidth;
  405.       height = bmih.biHeight;
  406.       bitCount = bmih.biBitCount;
  407.       imageSize = bmih.biSizeImage;
  408.       if (bitCount < 24 && (DWORD)bmih.biClrUsed == 0)
  409.         colourCount = 1 << bitCount;
  410.       else
  411.         colourCount = (PINDEX)(DWORD)bmih.biClrUsed;
  412.       for (PINDEX i = 0; i < colourCount; i++) {
  413.         P_RGBQUAD rgb(stream);
  414.         palette.SetColour(i, rgb);
  415.       }
  416.       break;
  417.     }
  418.     case 12 : {
  419.       P_BITMAPCOREHEADER bmch(stream);
  420.       if (!stream.good())
  421.         return;
  422.       width = (WORD)bmch.bcWidth;
  423.       height = (WORD)bmch.bcHeight;
  424.       bitCount = (WORD)bmch.bcBitCount;
  425.       imageSize = (width*bitCount+31)/32*height*4;
  426.       colourCount = 1 << bitCount;
  427.       for (PINDEX i = 0; i < colourCount; i++) {
  428.         P_RGBTRIPLE rgb(stream);
  429.         palette.SetColour(i, rgb);
  430.       }
  431.       break;
  432.     }
  433.     default :
  434.       return;
  435.   }
  436.   if (!stream.good())
  437.     return;
  438.   if (colourCount == 0) {
  439.     for (PINDEX i = 0; i < 256; i++) {
  440.       PColour col((BYTE)(i&0xe0), (BYTE)((i<<3)&0xe0), (BYTE)(i<<6));
  441.       palette.SetColour(i, col);
  442.     }
  443.   }
  444.   image = PPixelImage((PDIMENSION)width, (PDIMENSION)height, (BYTE)bitCount);
  445.   image->SetPalette(palette);
  446. #if defined(_WINDOWS) && !defined(_WIN32)
  447.   PPixelDataPtr pixPtr = image->GetPixelDataPtr();
  448.   while (imageSize > 0x4000) {
  449.     stream.read(pixPtr, 0x4000);
  450.     imageSize -= 0x4000;
  451.     pixPtr += 0x4000;
  452.   }
  453.   stream.read(pixPtr, (int)imageSize);
  454. #else
  455.   stream.read(image->GetPixelDataPtr(), imageSize);
  456. #endif
  457. }
  458. static int PPM_read_number(istream & stream)
  459. {
  460.   while (isspace(stream.peek()))
  461.     stream.get();
  462.   while (stream.peek() == '#') { // if the line is a comment, then ignore it
  463.     stream.ignore(P_MAX_INDEX, 'n');
  464.     while (isspace(stream.peek()))
  465.       stream.get();
  466.   }
  467.   // Read number 
  468.   int num;
  469.   stream >> num;
  470.   return num;
  471. }
  472. #if 0
  473. void PPixelImage::ReadPPM(istream & stream, BYTE format)
  474. {
  475.   // get the width and height
  476.   PDIMENSION width  = PPM_read_number(stream);
  477.   PDIMENSION height = PPM_read_number(stream);
  478.   PPalette palette;
  479.   BYTE bitCount;
  480.   // for each image type, we have to set depth and pixelData
  481.   int black, white, max_value;
  482.   switch (format) {
  483.     case '1':
  484.     case '4':
  485.       bitCount = 1;
  486.       max_value = -1;
  487.       black = palette.AddColour(PColour::Black);
  488.       white = palette.AddColour(PColour::White);
  489.       break;
  490.     case '2':
  491.     case '5':
  492.       bitCount = 8;
  493.       max_value = PPM_read_number(stream);
  494.       for (int i = 0; i < 128; i++)
  495.         palette.AddColour(PColour(i*2, i*2, i*2));
  496.       break;
  497.     case '3':
  498.     case '6':
  499.       bitCount = 24;
  500.       max_value = PPM_read_number(stream);
  501.       break;
  502.   }
  503.   PPixelImage pix(width, height, bitCount);
  504.   // calculate the shift for max_value
  505.   int shift;
  506.   if (max_value > 0) {
  507.     shift = 0;
  508.     while ((max_value << (shift+1)) < 255)
  509.       shift++;
  510.   }
  511.   // remove single whitespace after header if in raw format
  512.   if (format == '2' || format == '4' || format == '6')
  513.     stream.ignore();
  514.   int x, y;
  515.   // declare a line buffer when needed
  516.   PBYTEArray line(width * 3);
  517.   BYTE * linePtr = line.GetPointer();
  518.   switch (format) {
  519.     // PBM ASCII 
  520.     case '1':
  521.       for (y = 0; y < height; y++) {
  522.         for (x = 0; x < width; x++)
  523.           line[x] = PPM_read_number(stream);
  524.         operator->()->SetRaster(y, line, width);
  525.       }
  526.       break;
  527.     // PGM ASCII
  528.     case '2':
  529.       for (y = 0; y < height; y++) {
  530.         for (x = 0; x < width; x++)
  531.           line[x] = PPM_read_number(stream);
  532.         operator->()->SetRaster(y, line, width);
  533.       }
  534.       break;
  535.     // PPM ASCII
  536.     case '3':
  537.       for (y = 0; y < height; y++) {
  538.         for (x = 0; x < width*3; x++)
  539.           line[x] = PPM_read_number(stream);
  540.         operator->()->SetRaster(y, line, width);
  541.       }
  542.       break;
  543.     // PBM binary
  544.     case '4':
  545.       break;
  546.     // PGM binary
  547.     case '5':
  548.       break;
  549.     // PPM binary
  550.     case '6':
  551.       for (y = 0; y < height; y++) {
  552.         if (shift == 0)
  553.           file.Read (operator->()->GetRasterDataPtr(y), width*3);
  554.         else {
  555.           file.Read (linePtr, width*3);
  556.           BYTE * ptr = linePtr;
  557.           BYTE * optr = operator->()->GetRasterDataPtr(y);
  558.           for (PINDEX x = width; x > 0; x--)
  559.             *optr++ = *ptr++ << shift;
  560.         }
  561.       }
  562.       break;
  563.   }
  564. }
  565. #endif
  566. static void ReadPBMa(istream & stream, PPixelImage & image)
  567. {
  568.   PDIMENSION width  = PPM_read_number(stream);
  569.   PDIMENSION height = PPM_read_number(stream);
  570.   image = PPixelImage(width, height, 1);
  571.   PPalette pal;
  572.   pal.AddColour(PColour::Black);
  573.   pal.AddColour(PColour::White);
  574.   image->SetPalette(pal);
  575.   for (PDIMENSION y = 0; y < height; y++)
  576.     for (PDIMENSION x = 0; x < width; x++)
  577.       image->SetPixel(x, y, (BYTE)PPM_read_number(stream));
  578. }
  579. static void ReadPBMb(istream & stream, PPixelImage & image)
  580. {
  581.   PDIMENSION width  = PPM_read_number(stream);
  582.   PDIMENSION height = PPM_read_number(stream);
  583.   image = PPixelImage(width, height, 1);
  584.   PPalette pal;
  585.   pal.AddColour(PColour::Black);
  586.   pal.AddColour(PColour::White);
  587.   image->SetPalette(pal);
  588.   stream.ignore();  // Skip blank before binary data
  589.   for (PDIMENSION y = 0; y < height; y++) 
  590.     stream.read(image->GetRasterDataPtr(y), width);
  591. }
  592. static void ReadPGMa(istream & stream, PPixelImage & image)
  593. {
  594.   PDIMENSION width  = PPM_read_number(stream);
  595.   PDIMENSION height = PPM_read_number(stream);
  596.   /*int max_value =*/ PPM_read_number(stream);
  597.   image = PPixelImage(width, height, 8);
  598.   PPalette pal;
  599.   for (BYTE i = 0; i < 256; i += 2)
  600.     pal.AddColour(PColour(i, i, i));
  601.   image->SetPalette(pal);
  602.   for (PDIMENSION y = 0; y < height; y++)
  603.     for (PDIMENSION x = 0; x < width; x++)
  604.       image->SetPixel(x, y, (BYTE)PPM_read_number(stream));
  605. }
  606. static void ReadPGMb(istream & stream, PPixelImage & image)
  607. {
  608.   PDIMENSION width  = PPM_read_number(stream);
  609.   PDIMENSION height = PPM_read_number(stream);
  610.   int max_value = PPM_read_number(stream);
  611.   // calculate the shift for max_value
  612.   int shift = 0;
  613.   if (max_value > 0) {
  614.     while ((max_value << (shift+1)) < 255)
  615.       shift++;
  616.   }
  617.   image = PPixelImage(width, height, 8);
  618.   PPalette pal;
  619.   for (BYTE i = 0; i < 256; i += 2)
  620.     pal.AddColour(PColour(i, i, i));
  621.   image->SetPalette(pal);
  622.   stream.ignore();  // Skip blank before binary data
  623.   for (PDIMENSION y = 0; y < height; y++) {
  624.     BYTE * line = image->GetRasterDataPtr(y);
  625.     stream.read(line, width*3);
  626.     if (shift != 0) {
  627.       for (PINDEX x = width; x > 0; x--)
  628.         *line++ <<= shift;
  629.     }
  630.   }
  631. }
  632. static void ReadPPMa(istream & stream, PPixelImage & image)
  633. {
  634.   PDIMENSION width  = PPM_read_number(stream);
  635.   PDIMENSION height = PPM_read_number(stream);
  636.   /*int max_value =*/ PPM_read_number(stream);
  637.   image = PPixelImage(width, height, 24);
  638.   for (PDIMENSION y = 0; y < height; y++) {
  639.     BYTE * line = image->GetRasterDataPtr(y);
  640.     for (PDIMENSION x = 0; x < width*3; x++)
  641.       *line++ = (BYTE)PPM_read_number(stream);
  642.   }
  643. }
  644. static void ReadPPMb(istream & stream, PPixelImage & image)
  645. {
  646.   PDIMENSION width  = PPM_read_number(stream);
  647.   PDIMENSION height = PPM_read_number(stream);
  648.   int max_value = PPM_read_number(stream);
  649.   // calculate the shift for max_value
  650.   int shift = 0;
  651.   if (max_value > 0) {
  652.     while ((max_value << (shift+1)) < 255)
  653.       shift++;
  654.   }
  655.   image = PPixelImage(width, height, 24);
  656.   stream.ignore();  // Skip blank before binary data
  657.   for (PDIMENSION y = 0; y < height; y++) {
  658.     BYTE * line = image->GetRasterDataPtr(y);
  659.     stream.read(line, width*3);
  660.     if (shift != 0) {
  661.       for (PDIMENSION x = width; x > 0; x--)
  662.         *line++ <<= shift;
  663.     }
  664.   }
  665. }
  666. PPixelImage::PPixelImage(istream & stream)
  667. {
  668.   // read the magic number 
  669.   char magic[2];
  670.   stream.read(magic, 2);
  671.   if (!stream.good())
  672.     return;
  673.   // determine the format 
  674.   if (magic[0] == 'B' && magic[1] == 'M')
  675.     ReadBMP(stream, *this);
  676.   else if (magic[0] == 'P')
  677.     switch (magic[1]) {
  678.       case '1': // PBM ASCII 
  679.         ReadPBMa(stream, *this);
  680.         break;
  681.       case '2': // PGM ASCII
  682.         ReadPGMa(stream, *this);
  683.         break;
  684.       case '3': // PPM ASCII
  685.         ReadPPMa(stream, *this);
  686.         break;
  687.       case '4': // PBM binary
  688.         ReadPBMb(stream, *this);
  689.         break;
  690.       case '5': // PGM binary
  691.         ReadPGMb(stream, *this);
  692.         break;
  693.       case '6': // PPM binary
  694.         ReadPPMb(stream, *this);
  695.     }
  696. }
  697. void PPixelBase::SetDirtyArea(PORDINATE x, PORDINATE y, PDIMENSION width)
  698. {
  699.   PAssert(x >= 0 && (PDIMENSION)x < Width(), "Pixel out of bounds");
  700.   if (x < dirtyArea.Left())
  701.     dirtyArea.SetLeft(x);
  702.   if (x+(PORDINATE)width > dirtyArea.Right())
  703.     dirtyArea.SetRight(x+width);
  704.   if (y < dirtyArea.Top())
  705.     dirtyArea.SetTop(y);
  706.   if (y > dirtyArea.Bottom())
  707.     dirtyArea.SetBottom(y);
  708. }
  709. void PPixelBase::SetPixelColour(PORDINATE x,PORDINATE y,const PColour & colour)
  710. {
  711.   SetPixel(x, y, (BYTE)palette.GetIndex(colour));
  712. }
  713. void PPixels24::SetPixelColour(PORDINATE x,PORDINATE y,const PColour & colour)
  714. {
  715.   SetDirtyArea(x, y);
  716.   PPixelDataPtr pixel = GetRasterDataPtr(y) + x*3;
  717.   *pixel++ = colour.GetRed();
  718.   *pixel++ = colour.GetGreen();
  719.   *pixel   = colour.GetBlue();
  720. }
  721. void PPixels32::SetPixelColour(PORDINATE x,PORDINATE y,const PColour & colour)
  722. {
  723.   SetDirtyArea(x, y);
  724.   PPixelDataPtr pixel = GetRasterDataPtr(y) + x*4;
  725.   *pixel++ = colour.GetRed();
  726.   *pixel++ = colour.GetGreen();
  727.   *pixel++ = colour.GetBlue();
  728.   *pixel   = colour.GetAlpha();
  729. }
  730. void PPixels1::SetPixel(PORDINATE x, PORDINATE y, BYTE val)
  731. {
  732.   SetDirtyArea(x, y);
  733.   PPixelDataPtr pixel = GetRasterDataPtr(y) + (x >> 3);
  734.   x &= 7;
  735.   *pixel = (BYTE)((*pixel & ~(1 << x)) | (val << x));
  736. }
  737. void PPixels2::SetPixel(PORDINATE x, PORDINATE y, BYTE val)
  738. {
  739.   SetDirtyArea(x, y);
  740.   PPixelDataPtr pixel = GetRasterDataPtr(y) + (x >> 2);
  741.   x &= 3;
  742.   *pixel = (BYTE)((*pixel & ~(3 << x)) | (val << (x << 1)));
  743. }
  744. void PPixels4::SetPixel(PORDINATE x, PORDINATE y, BYTE val)
  745. {
  746.   SetDirtyArea(x, y);
  747.   PPixelDataPtr pixel = GetRasterDataPtr(y) + (x >> 1);
  748.   x &= 1;
  749.   *pixel = (BYTE)((*pixel & ~(0xf << x)) | (val << (x << 2)));
  750. }
  751. void PPixels8::SetPixel(PORDINATE x, PORDINATE y, BYTE val)
  752. {
  753.   SetDirtyArea(x, y);
  754.   PPixelDataPtr pixel = GetRasterDataPtr(y) + x;
  755.   *pixel = val;
  756. }
  757. void PPixels24::SetPixel(PORDINATE x, PORDINATE y, BYTE val)
  758. {
  759.   SetDirtyArea(x, y);
  760.   PPixelDataPtr pixel = GetRasterDataPtr(y) + x*3;
  761.   *pixel++ = val;
  762.   *pixel++ = val;
  763.   *pixel   = val;
  764. }
  765. void PPixels32::SetPixel(PORDINATE x, PORDINATE y, BYTE val)
  766. {
  767.   SetDirtyArea(x, y);
  768.   PPixelDataPtr pixel = GetRasterDataPtr(y) + x*4;
  769.   *pixel++ = val;
  770.   *pixel++ = val;
  771.   *pixel++ = val;
  772.   *pixel   = 0;
  773. }
  774. PColour PPixelBase::GetPixelColour(PORDINATE x, PORDINATE y) const
  775. {
  776.   return palette.GetColour(GetPixel(x, y));
  777. }
  778. PColour PPixels24::GetPixelColour(PORDINATE x, PORDINATE y) const
  779. {
  780.   PAssert(x >= 0 && (PDIMENSION)x < Width(), "Pixel out of bounds");
  781.   PPixelDataPtr pixel = GetRasterDataPtr(y) + x*3;
  782.   return PColour(pixel[0], pixel[1], pixel[2]);
  783. }
  784. PColour PPixels32::GetPixelColour(PORDINATE x, PORDINATE y) const
  785. {
  786.   PAssert(x >= 0 && (PDIMENSION)x < Width(), "Pixel out of bounds");
  787.   PPixelDataPtr pixel = GetRasterDataPtr(y) + x*4;
  788.   return PColour(pixel[0], pixel[1], pixel[2], pixel[3]);
  789. }
  790. BYTE PPixels1::GetPixel(PORDINATE x, PORDINATE y) const
  791. {
  792.   PAssert(x >= 0 && (PDIMENSION)x < Width(), "Pixel out of bounds");
  793.   PPixelDataPtr pixel = GetRasterDataPtr(y) + (x >> 3);
  794.   return (BYTE)((*pixel >> (x&7))&1);
  795. }
  796. BYTE PPixels2::GetPixel(PORDINATE x, PORDINATE y) const
  797. {
  798.   PAssert(x >= 0 && (PDIMENSION)x < Width(), "Pixel out of bounds");
  799.   PPixelDataPtr pixel = GetRasterDataPtr(y) + (x >> 2);
  800.   return (BYTE)((*pixel >> ((x&3) << 1))&3);
  801. }
  802. BYTE PPixels4::GetPixel(PORDINATE x, PORDINATE y) const
  803. {
  804.   PAssert(x >= 0 && (PDIMENSION)x < Width(), "Pixel out of bounds");
  805.   PPixelDataPtr pixel = GetRasterDataPtr(y) + (x >> 1);
  806.   return (BYTE)((*pixel >> ((x&1) << 2))&0xf);
  807. }
  808. BYTE PPixels8::GetPixel(PORDINATE x, PORDINATE y) const
  809. {
  810.   PAssert(x >= 0 && (PDIMENSION)x < Width(), "Pixel out of bounds");
  811.   PPixelDataPtr pixel = GetRasterDataPtr(y) + x;
  812.   return *pixel;
  813. }
  814. BYTE PPixels24::GetPixel(PORDINATE x, PORDINATE y) const
  815. {
  816.   PAssert(x >= 0 && (PDIMENSION)x < Width(), "Pixel out of bounds");
  817.   PPixelDataPtr pixel = GetRasterDataPtr(y) + x*3;
  818.   return (BYTE)((pixel[0]*30 + pixel[1]*59 + pixel[2]*11)/100);
  819. }
  820. BYTE PPixels32::GetPixel(PORDINATE x, PORDINATE y) const
  821. {
  822.   PAssert(x >= 0 && (PDIMENSION)x < Width(), "Pixel out of bounds");
  823.   PPixelDataPtr pixel = GetRasterDataPtr(y) + x*4;
  824.   return (BYTE)((pixel[0]*30 + pixel[1]*59 + pixel[2]*11)/100);
  825. }
  826. PPixelDataPtr PPixelBase::CalculateRaster(PORDINATE x, PORDINATE y,
  827.                                                      PDIMENSION & lastX) const
  828. {
  829.   PAssert(x >= 0 && (PDIMENSION)x < Width(), "Pixel out of bounds");
  830.   lastX += (PDIMENSION)x;
  831.   if (lastX > Width())
  832.     lastX = Width();
  833.   return GetRasterDataPtr(y) + x*GetDepth()/8;
  834. }
  835. void PPixelBase::SetRaster(PORDINATE x, PORDINATE y,
  836.                                   const PBYTEArray & raster, PDIMENSION width)
  837. {
  838.   if (width > (PDIMENSION)raster.GetSize())
  839.     width = (PDIMENSION)raster.GetSize();
  840.   SetRasterValues(x, y, raster, width);
  841. }
  842.   
  843. void PPixelBase::GetRaster(PORDINATE x, PORDINATE y,
  844.                                   PBYTEArray & raster, PDIMENSION width) const
  845. {
  846.   if (width > Width())
  847.     width = Width();
  848.   GetRasterValues(x, y, raster.GetPointer(width), width);
  849. }
  850.   
  851. void PPixelBase::SetRasterColours(PORDINATE x, PORDINATE y,
  852.                                 const PColourArray & raster, PDIMENSION width)
  853. {
  854.   if (width > (PDIMENSION)raster.GetSize())
  855.     width = (PDIMENSION)raster.GetSize();
  856.   while ((PDIMENSION)x < width) {
  857.     SetPixel(x, y, (BYTE)palette.GetIndex(raster[x]));
  858.     x++;
  859.   }
  860. }
  861. void PPixels24::SetRasterColours(PORDINATE x, PORDINATE y,
  862.                                 const PColourArray & raster, PDIMENSION width)
  863. {
  864.   if (width > (PDIMENSION)raster.GetSize())
  865.     width = (PDIMENSION)raster.GetSize();
  866.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  867.   SetDirtyArea(x, y, width);
  868.   while ((PDIMENSION)x < width) {
  869.     *pixel++ = raster[x].GetRed();
  870.     *pixel++ = raster[x].GetGreen();
  871.     *pixel++ = raster[x++].GetBlue();
  872.   }
  873. }
  874. void PPixels32::SetRasterColours(PORDINATE x, PORDINATE y,
  875.                                 const PColourArray & raster, PDIMENSION width)
  876. {
  877.   if (width > (PDIMENSION)raster.GetSize())
  878.     width = (PDIMENSION)raster.GetSize();
  879.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  880.   SetDirtyArea(x, y, width);
  881.   while ((PDIMENSION)x < width) {
  882.     *pixel++ = raster[x].GetRed();
  883.     *pixel++ = raster[x].GetGreen();
  884.     *pixel++ = raster[x].GetBlue();
  885.     *pixel++ = raster[x++].GetAlpha();
  886.   }
  887. }
  888. void PPixels1::SetRasterValues(PORDINATE x, PORDINATE y,
  889.                                         const BYTE * raster, PDIMENSION width)
  890. {
  891.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  892.   BYTE mask = (BYTE)(0x80 >> (x&7));
  893.   *pixel = 0;
  894.   while ((PDIMENSION)x < width) {
  895.     if (*raster++ != 0)
  896.       *pixel |= mask;
  897.     mask >>= 1;
  898.     if (mask == 0) {
  899.       *++pixel = 0;
  900.       mask = 0x80;
  901.     }
  902.     x++;
  903.   }
  904. }
  905. void PPixels2::SetRasterValues(PORDINATE x, PORDINATE y,
  906.                                         const BYTE * raster, PDIMENSION width)
  907. {
  908.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  909.   SetDirtyArea(x, y, width);
  910.   while ((PDIMENSION)(x += 4) <= width) {
  911.     *pixel++ = (BYTE)((raster[0] << 6)|(raster[1] << 4)|
  912.                       (raster[2] << 2)| raster[3]);
  913.     raster += 4;
  914.   }
  915.   switch (x&3) {
  916.     case 1 :
  917.       *pixel = (BYTE)((raster[0] << 6)|(raster[1] << 4)|
  918.                         (raster[2] << 2));
  919.       break;
  920.     case 2 :
  921.       *pixel = (BYTE)((raster[0] << 6)|(raster[1] << 4));
  922.       break;
  923.     case 3 :
  924.       *pixel = (BYTE)(raster[0] << 6);
  925.       break;
  926.   }
  927. }
  928. void PPixels4::SetRasterValues(PORDINATE x, PORDINATE y,
  929.                                         const BYTE * raster, PDIMENSION width)
  930. {
  931.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  932.   SetDirtyArea(x, y, width);
  933.   while ((PDIMENSION)(x += 2) <= width) {
  934.     *pixel++ = (BYTE)((raster[0] << 4)|raster[1]);
  935.     raster += 2;
  936.   }
  937.   if ((x&1) != 0)
  938.     *pixel = (BYTE)(*raster << 4);
  939. }
  940. void PPixels8::SetRasterValues(PORDINATE x, PORDINATE y,
  941.                                         const BYTE * raster, PDIMENSION width)
  942. {
  943.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  944.   SetDirtyArea(x, y, width);
  945.   memcpy(pixel, raster, width);
  946. }
  947. void PPixels24::SetRasterValues(PORDINATE x, PORDINATE y,
  948.                                         const BYTE * raster, PDIMENSION width)
  949. {
  950.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  951.   SetDirtyArea(x, y, width);
  952.   while ((PDIMENSION)x < width) {
  953.     *pixel++ = *raster;
  954.     *pixel++ = *raster;
  955.     *pixel++ = *raster;
  956.     raster++;
  957.     x++;
  958.   }
  959. }
  960. void PPixels32::SetRasterValues(PORDINATE x, PORDINATE y,
  961.                                         const BYTE * raster, PDIMENSION width)
  962. {
  963.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  964.   SetDirtyArea(x, y, width);
  965.   while ((PDIMENSION)x < width) {
  966.     *pixel++ = *raster;
  967.     *pixel++ = *raster;
  968.     *pixel++ = *raster;
  969.     *pixel++ = 0;
  970.     raster++;
  971.     x++;
  972.   }
  973. }
  974. void PPixelBase::GetRasterColours(PORDINATE x, PORDINATE y,
  975.                                 PColourArray & raster, PDIMENSION width) const
  976. {
  977.   CalculateRaster(x, y, width);
  978.   raster.SetMinSize(width);
  979.   while ((PDIMENSION)x < width) {
  980.     raster[x] = palette.GetColour(GetPixel(x, y));
  981.     x++;
  982.   }
  983. }
  984. void PPixels24::GetRasterColours(PORDINATE x, PORDINATE y,
  985.                                 PColourArray & raster, PDIMENSION width) const
  986. {
  987.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  988.   raster.SetMinSize(width);
  989.   while ((PDIMENSION)x < width) {
  990.     raster[x++] = PColour(pixel[0], pixel[1], pixel[2]);
  991.     pixel += 3;
  992.   }
  993. }
  994. void PPixels32::GetRasterColours(PORDINATE x, PORDINATE y,
  995.                                 PColourArray & raster, PDIMENSION width) const
  996. {
  997.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  998.   raster.SetMinSize(width);
  999.   while ((PDIMENSION)x < width) {
  1000.     raster[x++] = PColour(pixel[0], pixel[1], pixel[2], pixel[3]);
  1001.     pixel += 4;
  1002.   }
  1003. }
  1004. void PPixels1::GetRasterValues(PORDINATE x, PORDINATE y,
  1005.                                         BYTE * raster, PDIMENSION width) const
  1006. {
  1007.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  1008.   int mask = 0x80 >> (x&7);
  1009.   *pixel = 0;
  1010.   while ((PDIMENSION)x < width) {
  1011.     *raster++ = (BYTE)((*pixel & mask) != 0);
  1012.     mask >>= 1;
  1013.     if (mask == 0) {
  1014.       *++pixel = 0;
  1015.       mask = 0x80;
  1016.     }
  1017.     x++;
  1018.   }
  1019. }
  1020. void PPixels2::GetRasterValues(PORDINATE x, PORDINATE y,
  1021.                                         BYTE * raster, PDIMENSION width) const
  1022. {
  1023.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  1024.   while ((PDIMENSION)x < width) {
  1025.     *raster++ = (BYTE)(*pixel >> 6);
  1026.     if ((PDIMENSION)++x < width) {
  1027.       *raster++ = (BYTE)((*pixel >> 4)&3);
  1028.       if ((PDIMENSION)++x < width) {
  1029.         *raster++ = (BYTE)((*pixel >> 2)&3);
  1030.         if ((PDIMENSION)++x < width)
  1031.           *raster++ = (BYTE)(*pixel&3);
  1032.       }
  1033.     }
  1034.     pixel++;
  1035.   }
  1036. }
  1037. void PPixels4::GetRasterValues(PORDINATE x, PORDINATE y,
  1038.                                         BYTE * raster, PDIMENSION width) const
  1039. {
  1040.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  1041.   while ((PDIMENSION)x < width) {
  1042.     *raster++ = (BYTE)(*pixel >> 4);
  1043.     if ((PDIMENSION)++x < width)
  1044.       *raster++ = (BYTE)(*pixel&0xf);
  1045.     pixel++;
  1046.   }
  1047. }
  1048. void PPixels8::GetRasterValues(PORDINATE x, PORDINATE y,
  1049.                                         BYTE * raster, PDIMENSION width) const
  1050. {
  1051.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  1052.   memcpy(raster, pixel, width);
  1053. }
  1054. void PPixels24::GetRasterValues(PORDINATE x, PORDINATE y,
  1055.                                         BYTE * raster, PDIMENSION width) const
  1056. {
  1057.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  1058.   while ((PDIMENSION)x < width) {
  1059.     *raster++ = (BYTE)((pixel[0]*30 + pixel[1]*59 + pixel[2]*11)/100);
  1060.     pixel += 3;
  1061.     x++;
  1062.   }
  1063. }
  1064. void PPixels32::GetRasterValues(PORDINATE x, PORDINATE y,
  1065.                                         BYTE * raster, PDIMENSION width) const
  1066. {
  1067.   PPixelDataPtr pixel = CalculateRaster(x, y, width);
  1068.   while ((PDIMENSION)x < width) {
  1069.     *raster++ = (BYTE)((pixel[0]*30 + pixel[1]*59 + pixel[2]*11)/100);
  1070.     pixel += 4;
  1071.     x++;
  1072.   }
  1073. }
  1074. PPixelImage PPixelBase::ExtractPixels(PORDINATE x, PORDINATE y,
  1075.                                    PDIMENSION width, PDIMENSION height) const
  1076. {
  1077.   PAssert(x >= 0 && (PDIMENSION)x < Width() &&
  1078.           y >= 0 && (PDIMENSION)y < Height(), "Pixel out of bounds");
  1079.   if (width > Width() - x)
  1080.     width = Width() - x;
  1081.   if (height > Height() - y)
  1082.     height = Height() - y;
  1083.   PPixelImage pix(width, height, GetDepth());
  1084.   if (GetDepth() >= 8 || x%(8/GetDepth()) == 0) {
  1085.     for (PDIMENSION py = 0; py < height; py++)
  1086.       memcpy(pix->GetRasterDataPtr(py),
  1087.                  GetRasterDataPtr(y++) + x*GetDepth()/8, pix->pixelLineBytes);
  1088.   }
  1089.   else {
  1090.     PBYTEArray raster(width);
  1091.     for (PDIMENSION py = 0; py < height; py++) {
  1092.       GetRaster(x, y++, raster, width);
  1093.       pix->SetRaster(py, raster, width);
  1094.     }
  1095.   }
  1096.   return pix;
  1097. }
  1098. //////////////////////////////////////////////////////////////////////////////
  1099. // PCanvasState
  1100. #if defined(_PCANVASSTATE)
  1101. PCanvasState::PCanvasState()
  1102.   : penStyle(PCanvas::Solid),
  1103.     penWidth(0),
  1104.     penMode(PCanvas::SrcCopy),
  1105.     penFgColour(PColour::Black),
  1106.     penBkColour(PColour::White),
  1107.     fillFgColour(PColour::Clear),
  1108.     fillBkColour(PColour::Clear),
  1109.     fillMode(PCanvas::SrcCopy),
  1110.     font("System", 10),
  1111.     textFgColour(PColour::Black),
  1112.     textBkColour(PColour::White),
  1113.     palette(),
  1114.     polyFillMode(PCanvas::Winding),
  1115.     viewport(0, 0, 100, 100), 
  1116.     map(0, 0, 100, 100)
  1117. {
  1118. }
  1119. PCanvasState::PCanvasState(const PCanvasState & s)
  1120.   : penStyle(s.penStyle),
  1121.     penWidth(s.penWidth),
  1122.     penMode(s.penMode),
  1123.     penFgColour(s.penFgColour),
  1124.     penBkColour(s.penBkColour),
  1125.     fillFgColour(s.fillFgColour),
  1126.     fillBkColour(s.fillBkColour),
  1127.     fillPattern(s.fillPattern),
  1128.     fillMode(s.fillMode),
  1129.     font(s.font),
  1130.     textFgColour(s.textFgColour),
  1131.     textBkColour(s.textBkColour),
  1132.     palette(s.palette),
  1133.     polyFillMode(s.polyFillMode),
  1134.     viewport(s.viewport), 
  1135.     map(s.map)
  1136. {
  1137. }
  1138. BOOL PCanvasState::SetPenStyle(PenStyles style)
  1139. {
  1140.   if (penStyle == style)
  1141.     return FALSE;
  1142.   penStyle = style;
  1143.   return TRUE;
  1144. }
  1145. BOOL PCanvasState::SetPenWidth(int width)
  1146. {
  1147.   if (penWidth == width)
  1148.     return FALSE;
  1149.   penWidth = width;
  1150.   return TRUE;
  1151. }
  1152. BOOL PCanvasState::SetPenMode(DrawingModes mode)
  1153. {
  1154.   if (penMode == mode)
  1155.     return FALSE;
  1156.   penMode = mode;
  1157.   return TRUE;
  1158. }
  1159. BOOL PCanvasState::SetPenFgColour(const PColour & colour)
  1160. {
  1161.   if (colour == penFgColour)
  1162.     return FALSE;
  1163.   penFgColour = colour;
  1164.   return TRUE;
  1165. }
  1166. BOOL PCanvasState::SetPenBkColour(const PColour & colour)
  1167. {
  1168.   if (colour == penBkColour)
  1169.     return FALSE;
  1170.   penBkColour = colour;
  1171.   return TRUE;
  1172. }
  1173. BOOL PCanvasState::SetFillPattern(const PPattern & pattern)
  1174. {
  1175.   if (fillPattern == pattern)
  1176.     return FALSE;
  1177.   fillPattern = pattern;
  1178.   return TRUE;
  1179. }
  1180. BOOL PCanvasState::SetPatternOrigin(const PPoint & pt)
  1181. {
  1182.   if (patternOrigin == pt)
  1183.     return FALSE;
  1184.   patternOrigin = pt;
  1185.   return TRUE;
  1186. }
  1187. BOOL PCanvasState::SetFillMode(DrawingModes mode)
  1188. {
  1189.   if (fillMode == mode)
  1190.     return FALSE;
  1191.   fillMode = mode;
  1192.   return TRUE;
  1193. }
  1194. BOOL PCanvasState::SetFillFgColour(const PColour & colour)
  1195. {
  1196.   if (colour == fillFgColour)
  1197.     return FALSE;
  1198.   fillFgColour = colour;
  1199.   return TRUE;
  1200. }
  1201. BOOL PCanvasState::SetFillBkColour(const PColour & colour)
  1202. {
  1203.   if (colour == fillBkColour)
  1204.     return FALSE;
  1205.   fillBkColour = colour;
  1206.   return TRUE;
  1207. }
  1208. BOOL PCanvasState::SetFont(const PFont & newFont)
  1209. {
  1210.   if (font == newFont)
  1211.     return FALSE;
  1212.   font = newFont;
  1213.   return TRUE;
  1214. }
  1215. BOOL PCanvasState::SetTextFgColour(const PColour & colour)
  1216. {
  1217.   if (colour == textFgColour)
  1218.     return FALSE;
  1219.   textFgColour = colour;
  1220.   return TRUE;
  1221. }
  1222. BOOL PCanvasState::SetTextBkColour(const PColour & colour)
  1223. {
  1224.   if (colour == textBkColour)
  1225.     return FALSE;
  1226.   textBkColour = colour;
  1227.   return TRUE;
  1228. }
  1229. BOOL PCanvasState::SetPalette(const PPalette & newPal)
  1230. {
  1231.   if (palette == newPal)
  1232.     return FALSE;
  1233.   palette = newPal;
  1234.   return TRUE;
  1235. }
  1236. BOOL PCanvasState::SetPolyFillMode(PolyFillMode newMode)
  1237. {
  1238.   if (polyFillMode == newMode)
  1239.     return FALSE;
  1240.   polyFillMode = newMode;
  1241.   return TRUE;
  1242. }
  1243. BOOL PCanvasState::SetViewportRect(const PRect & rect)
  1244. {
  1245.   if (viewport == rect)
  1246.     return FALSE;
  1247.   viewport = rect;
  1248.   return TRUE;
  1249. }
  1250. BOOL PCanvasState::SetMappingRect(const PRect & rect)
  1251. {
  1252.   if (map == rect)
  1253.     return FALSE;
  1254.   map = rect;
  1255.   return TRUE;
  1256. }
  1257. void PCanvasState::SetOrigin(const PPoint & pt)
  1258. {
  1259.   PRect newMap = map;
  1260.   newMap.SetOrigin(pt);
  1261.   SetMappingRect(newMap);
  1262. }
  1263. #endif
  1264. //////////////////////////////////////////////////////////////////////////////
  1265. // PCanvas
  1266. #if defined(_PCANVAS)
  1267. inline static long CalculateScaledValue(long value,
  1268.                                         int innerOffset, int innerWidth,
  1269.                                         int outerOffset, int outerWidth)
  1270. {
  1271.   long tmp = (1000L*(value-innerOffset)*outerWidth)/innerWidth;
  1272.   if (tmp < 0)
  1273.     tmp -= 500;
  1274.   else
  1275.     tmp += 500;
  1276.   return tmp/1000L + outerOffset;
  1277. }
  1278. PDIMENSION PCanvas::FromPixelsDX(PDIMENSION dx) const
  1279. {
  1280.   return (PDIMENSION)CalculateScaledValue(dx,
  1281.                                           0, viewport.Width(), 0, map.Width());
  1282. }
  1283. PDIMENSION PCanvas::FromPixelsDY(PDIMENSION dy) const
  1284. {
  1285.   return (PDIMENSION)CalculateScaledValue(dy,
  1286.                                         0, viewport.Height(), 0, map.Height());
  1287. }
  1288. PORDINATE PCanvas::FromPixelsX(PORDINATE x) const
  1289. {
  1290.   return (PORDINATE)CalculateScaledValue(x,
  1291.                          viewport.X(), viewport.Width(), map.X(), map.Width());
  1292. }
  1293. PORDINATE PCanvas::FromPixelsY(PORDINATE y) const
  1294. {
  1295.   return (PORDINATE)CalculateScaledValue(y,
  1296.                        viewport.Y(), viewport.Height(), map.Y(), map.Height());
  1297. }
  1298. PDIMENSION PCanvas::ToPixelsDX(PDIMENSION dx) const
  1299. {
  1300.   return (PDIMENSION)CalculateScaledValue(dx,
  1301.                                           0, map.Width(), 0, viewport.Width());
  1302. }
  1303. PDIMENSION PCanvas::ToPixelsDY(PDIMENSION dy) const
  1304. {
  1305.   return (PDIMENSION)CalculateScaledValue(dy,
  1306.                                         0, map.Height(), 0, viewport.Height());
  1307. }
  1308. PORDINATE PCanvas::ToPixelsX(PORDINATE x) const
  1309. {
  1310.   return (PORDINATE)CalculateScaledValue(x,
  1311.                          map.X(), map.Width(), viewport.X(), viewport.Width());
  1312. }
  1313. PORDINATE PCanvas::ToPixelsY(PORDINATE y) const
  1314. {
  1315.   return (PORDINATE)CalculateScaledValue(y,
  1316.                        map.Y(), map.Height(), viewport.Y(), viewport.Height());
  1317. }
  1318. PDIMENSION PCanvas::ToPointsX(PDIMENSION x)
  1319. {
  1320.   long tmp1 = 7200L*x*viewport.Width();
  1321.   long tmp2 = map.Width()*deviceResX*100L;
  1322.   if (tmp1 < 0)
  1323.     tmp1 -= tmp2/2;
  1324.   else
  1325.     tmp1 += tmp2/2;
  1326.   return (PDIMENSION)(tmp1/tmp2);
  1327. }
  1328.   
  1329. PDIMENSION PCanvas::ToPointsY(PDIMENSION y)
  1330. {
  1331.   long tmp1 = 7200L*y*viewport.Height();
  1332.   long tmp2 = map.Height()*deviceResY*100L;
  1333.   if (tmp1 < 0)
  1334.     tmp1 -= tmp2/2;
  1335.   else
  1336.     tmp1 += tmp2/2;
  1337.   return (PDIMENSION)(tmp1/tmp2);
  1338. }
  1339. PDIMENSION PCanvas::FromPointsX(PDIMENSION x)
  1340. {
  1341.   long tmp = (100L*x*deviceResX*map.Width())/viewport.Width();
  1342.   if (tmp < 0)
  1343.     tmp -= 3600;
  1344.   else
  1345.     tmp += 3600;
  1346.   return (PDIMENSION)(tmp/7200L);
  1347. }
  1348.   
  1349. PDIMENSION PCanvas::FromPointsY(PDIMENSION y)
  1350. {
  1351.   long tmp = (100L*y*deviceResY*map.Height())/viewport.Height();
  1352.   if (tmp < 0)
  1353.     tmp -= 3600;
  1354.   else
  1355.     tmp += 3600;
  1356.   return (PDIMENSION)(tmp/7200L);
  1357. }
  1358.   
  1359. void PCanvas::DrawBevelledRect(const PRect & rect, BOOL raised, BOOL deep)
  1360. {
  1361.   Save();
  1362.   PRect bounds = ToPixels(rect);
  1363.   PDim border = PApplication::Current().GetBorderSize();
  1364.   SetMappingRect(GetViewportRect());
  1365.   const PColour & shadowColour = PApplication::Current().GetButtonShadowColour();
  1366.   const PColour & lightColour = PApplication::Current().GetButtonLightingColour();
  1367.   const PColour & bkColour = GetFillFgColour();
  1368.   SetPenFgColour(bkColour);
  1369.   SetFillFgColour(bkColour);
  1370.   SetFillBkColour(bkColour);
  1371.   DrawRect(bounds);
  1372.   PORDINATE left = bounds.Left();
  1373.   PORDINATE top = bounds.Top();
  1374.   PORDINATE right = bounds.Right()-border.Width();
  1375.   PORDINATE bottom = bounds.Bottom()-border.Height();
  1376.   if (raised)
  1377.     SetPenFgColour(shadowColour);
  1378.   else
  1379.     SetPenFgColour(lightColour);
  1380.   SetPenWidth(border.Height());
  1381.   DrawLine(left,  bottom, right+border.Width(), bottom);
  1382.   bottom -= border.Height();
  1383.   if (deep)
  1384.     DrawLine(left+border.Width(), bottom, right+border.Width(), bottom);
  1385.   SetPenWidth(border.Width());
  1386.   DrawLine(right, top, right, bottom+border.Height());
  1387.   right -= border.Width();
  1388.   if (deep)
  1389.     DrawLine(right, top+border.Height(), right, bottom+border.Height());
  1390.   if (raised)
  1391.     SetPenFgColour(lightColour);
  1392.   else
  1393.     SetPenFgColour(shadowColour);
  1394.   SetPenWidth(border.Width());
  1395.   DrawLine(left,  top, left, bottom+border.Height());
  1396.   left += border.Width();
  1397.   if (deep)
  1398.     DrawLine(left,  top, left, bottom);
  1399.   SetPenWidth(border.Height());
  1400.   DrawLine(left, top, right+border.Width(), top);
  1401.   if (deep) {
  1402.     top += border.Height();
  1403.     DrawLine(left, top, right, top);
  1404.   }
  1405.   Restore();
  1406. }
  1407. static PString AddEllipses(PCanvas & canvas,
  1408.                         PDIMENSION width, const PString & line, int alignment)
  1409. {
  1410.   int amtTooBig = canvas.MeasureString(line).Width() - width;
  1411.   if (amtTooBig <= 0)
  1412.     return line;
  1413.   PDIMENSION fontWidth = canvas.FromPointsY(canvas.GetFont().GetAvgWidth());
  1414.   PINDEX numChars = line.GetLength() - (amtTooBig+fontWidth-1)/fontWidth - 5;
  1415.   PString ellipses, str;
  1416.   switch (alignment) {
  1417.     default :
  1418.     case PCanvas::LeftAlign :
  1419.       ellipses = " ...";
  1420.       str = line.Left(numChars) + ellipses;
  1421.       break;
  1422.     case PCanvas::RightAlign :
  1423.       ellipses = "... ";
  1424.       str = ellipses + line.Right(numChars);
  1425.       break;
  1426.     case PCanvas::Centred :
  1427.       ellipses = " ... ";
  1428.       str = line.Left((numChars+1)/2) + ellipses + line.Right(numChars/2);
  1429.       break;
  1430.   }
  1431.   while (canvas.MeasureString(str).Width() - width <= 0) {
  1432.     numChars++;
  1433.     switch (alignment) {
  1434.       default :
  1435.       case PCanvas::LeftAlign :
  1436.         str = line.Left(numChars) + ellipses;
  1437.         break;
  1438.       case PCanvas::RightAlign :
  1439.         str = ellipses + line.Right(numChars);
  1440.         break;
  1441.       case PCanvas::Centred :
  1442.         str = line.Left((numChars+1)/2) + ellipses + line.Right(numChars/2);
  1443.         break;
  1444.     }
  1445.   }
  1446.   numChars--;
  1447.   switch (alignment) {
  1448.     default :
  1449.     case PCanvas::LeftAlign :
  1450.       return line.Left(numChars) + ellipses;
  1451.     case PCanvas::RightAlign :
  1452.       return ellipses + line.Right(numChars);
  1453.     case PCanvas::Centred :
  1454.       return line.Left((numChars+1)/2) + ellipses + line.Right(numChars/2);
  1455.   }
  1456. }
  1457. PDIMENSION PCanvas::DrawString(const PRect & rect, const PString & str, int options) 
  1458. {
  1459.   if (GetTextBkColour().GetAlpha() != 0) {
  1460.     Save();
  1461.     SetPenStyle(Solid);
  1462.     SetPenWidth(0);
  1463.     SetPenMode(SrcCopy);
  1464.     SetPenFgColour(GetTextBkColour());
  1465.     SetFillPattern(PPattern());
  1466.     SetFillMode(SrcCopy);
  1467.     SetFillFgColour(GetTextBkColour());
  1468.     DrawRect(rect);
  1469.     Restore();
  1470.   }
  1471.   PDIMENSION spaceWidth = MeasureString(" ").Width();
  1472.   PStringArray unbrokenLines = str.Lines();
  1473.   PStringArray lines(unbrokenLines.GetSize());
  1474.   PINDEX line = 0;
  1475.   for (PINDEX i = 0; i < unbrokenLines.GetSize(); i++) {
  1476.     if (MeasureString(unbrokenLines[i]).Width() <= rect.Width())
  1477.       lines[line++] = unbrokenLines[i];
  1478.     else {
  1479.       switch (options&HorizontalWrapMask) {
  1480.         case NoWrapping :
  1481.           lines[line++] = unbrokenLines[i];
  1482.           break;
  1483.         // break the lines into new lines that are no wider than the rectangle
  1484.         case WordWrap : {
  1485.           PString str;
  1486.           PDIMENSION w = 0;
  1487.           PStringArray words = unbrokenLines[i].Tokenise(" t", FALSE);
  1488.           for (PINDEX k = 0; k < words.GetSize(); k++) {
  1489.             PDIMENSION x = MeasureString(words[k]).Width();
  1490.             if (w + x > rect.Width()) {
  1491.               if (w != 0)
  1492.                 lines[line++] = str;
  1493.               str = "";
  1494.               w = 0;
  1495.             }
  1496.             else if (w != 0) {
  1497.               str += " ";
  1498.               x += spaceWidth;
  1499.             }
  1500.             str += words[k];
  1501.             w += x;
  1502.           }
  1503.           lines[line++] = str;
  1504.           break;
  1505.         }
  1506.         // Chop text out of the line so that is no wider than the rectangle
  1507.         case CentreEllipses :
  1508.           lines[line++] = AddEllipses(*this,
  1509.                                       rect.Width(), unbrokenLines[i], Centred);
  1510.           break;
  1511.         case EndEllipses :
  1512.           lines[line++] = AddEllipses(*this,
  1513.               rect.Width(), unbrokenLines[i], options&HorizontalAlignmentMask);
  1514.           break;
  1515.       }
  1516.     }
  1517.   }
  1518.   PDIMENSION fontHeight = FromPointsY(realFont.GetHeight());
  1519.   PDIMENSION totalHeight = fontHeight*lines.GetSize();
  1520.   if (totalHeight > rect.Height()) {
  1521.     int numLinesToKill = (totalHeight-rect.Height()+fontHeight-1)/fontHeight+1;
  1522.     int firstLineToKill;
  1523.     switch (options&VerticalTruncationMask) {
  1524.       case CentreTruncation :
  1525.         firstLineToKill = lines.GetSize()/2 - numLinesToKill/2;
  1526.         break;
  1527.       case EndTruncation :
  1528.         switch (options&VerticalAlignmentMask) {
  1529.           case PCanvas::TopAlign :
  1530.             firstLineToKill = lines.GetSize() - numLinesToKill;
  1531.             break;
  1532.           case PCanvas::CentreVertical :
  1533.             firstLineToKill = lines.GetSize()/2 - numLinesToKill/2;
  1534.             break;
  1535.           default : // BottomAlign and BaseLine
  1536.             firstLineToKill = 0;
  1537.         }
  1538.         break;
  1539.       default :
  1540.         firstLineToKill = numLinesToKill = 0;
  1541.     }
  1542.     if (numLinesToKill > 0) {
  1543.       PDIMENSION eWidth = MeasureString(" ... ").Width();
  1544.       PString s = AddEllipses(*this, rect.Width()/2-eWidth/2,
  1545.                                           lines[firstLineToKill], LeftAlign) +
  1546.                   " ... " +
  1547.                   AddEllipses(*this, rect.Width()/2-eWidth/2,
  1548.                          lines[firstLineToKill+numLinesToKill-1], RightAlign);
  1549.       while (numLinesToKill-- > 0)
  1550.         lines.RemoveAt(firstLineToKill);
  1551.       lines.InsertAt(firstLineToKill, new PString(s));
  1552.       totalHeight = fontHeight*lines.GetSize();
  1553.     }
  1554.   }
  1555.   PORDINATE y;
  1556.   switch (options&VerticalAlignmentMask) {
  1557.     case TopAlign :
  1558.       y = rect.Top();
  1559.       break;
  1560.     case CentreVertical :
  1561.       y = rect.Top() + (rect.Height()-totalHeight)/2;
  1562.       break;
  1563.     default : // BottomAlign and BaseLine
  1564.       y = rect.Bottom() - totalHeight;
  1565.   }
  1566.   for (line = 0; line < lines.GetSize(); line++, y += fontHeight) {
  1567.     switch (options&HorizontalAlignmentMask) {
  1568.       case LeftAlign :
  1569.         DrawString(rect.Left(), y, lines[line], LeftAlign);
  1570.         break;
  1571.       
  1572.       case RightAlign :
  1573.         DrawString(rect.Right(), y, lines[line], RightAlign);
  1574.         break;
  1575.       
  1576.       case Centred :
  1577.         DrawString((rect.Left()+rect.Right())/2, y, lines[line], Centred);
  1578.         break;
  1579.       
  1580.       case Justified :
  1581.         // Split the line into space separated words
  1582.         PStringArray words = lines[line].Tokenise(" ", FALSE);
  1583.         if (words.GetSize() <= 1)
  1584.           DrawString(rect.Left(), y, lines[line], LeftAlign);
  1585.         else {
  1586.           // Now get the width inpixesl of each word
  1587.           PWORDArray wordWidths(words.GetSize());
  1588.           PDIMENSION totalWidth = 0;
  1589.           PINDEX word;
  1590.           for (word = 0; word < words.GetSize(); word++) {
  1591.             wordWidths[word] = (WORD)MeasureString(words[word]).Width();
  1592.             totalWidth += wordWidths[word];
  1593.           }
  1594.           if (rect.Width() <= totalWidth)
  1595.             DrawString(rect.Left(), y, lines[line], LeftAlign);
  1596.           else {
  1597.             // Now calculate the size of each space
  1598.             PORDINATE spaceWidth = (rect.Width()-totalWidth)/(words.GetSize()-1);
  1599.             // Finally, output each word at x location determined by space width
  1600.             PORDINATE x = rect.Left();
  1601.             for (word = 0; word < words.GetSize(); word++) {
  1602.               DrawString(x, y, words[word], LeftAlign);
  1603.               x += wordWidths[word] + spaceWidth;
  1604.             }
  1605.           }
  1606.         }
  1607.     }
  1608.   }
  1609.   return lines.GetSize()*fontHeight;
  1610. }
  1611. PDIMENSION PCanvas::MeasureString(const PString & str, PDIMENSION width)
  1612. {
  1613.   PStringArray lines = str.Lines();
  1614.   PDIMENSION height = 0;
  1615.   for (PINDEX line = 0; line < lines.GetSize(); line++) {
  1616.     PDim lineDim(MeasureString(lines[line]));
  1617.     if (lineDim.Width() > width) {
  1618.       
  1619.     }
  1620.     height += lineDim.Height();
  1621.   }
  1622.   return height;
  1623. }
  1624. void PCanvas::Restore()
  1625. {
  1626.   State * old = stack.Pop();
  1627.   SetPenStyle(old->GetPenStyle());
  1628.   SetPenWidth(old->GetPenWidth());
  1629.   SetPenMode(old->GetPenMode());
  1630.   SetPenFgColour(old->GetPenFgColour());
  1631.   SetPenBkColour(old->GetPenBkColour());
  1632.   SetFillFgColour(old->GetFillFgColour());
  1633.   SetFillBkColour(old->GetFillBkColour());
  1634.   SetFillPattern(old->GetFillPattern());
  1635.   SetFillMode(old->GetFillMode());
  1636.   SetFont(old->font);
  1637.   SetTextFgColour(old->GetTextFgColour());
  1638.   SetTextBkColour(old->GetTextBkColour());
  1639.   SetPalette(old->GetPalette());
  1640.   SetPolyFillMode(old->GetPolyFillMode());
  1641.   SetViewportRect(old->GetViewportRect());
  1642.   SetMappingRect(old->GetMappingRect());
  1643.   delete old;
  1644. }
  1645. #endif
  1646. //////////////////////////////////////////////////////////////////////////////
  1647. // PInteractorCanvas
  1648. #if defined(_PINTERACTORCANVAS)
  1649. void PInteractorCanvas::Construct(BOOL inPixels)
  1650. {
  1651.   PCanvasState::SetMappingRect(PRect(0, 0, 100, 100));
  1652.   if (inPixels)
  1653.     PCanvasState::SetViewportRect(map);
  1654.   else
  1655.     PCanvasState::SetViewportRect(PRect(0, 0,
  1656.                           (PDIMENSION)interactor->ToPixelsX(100),
  1657.                           (PDIMENSION)interactor->ToPixelsY(100)));
  1658.   const PColour & fgColour = interactor->GetForegroundColour();
  1659.   const PColour & bkColour = interactor->GetBackgroundColour();
  1660.   PCanvasState::SetPenFgColour(fgColour);
  1661.   PCanvasState::SetPenBkColour(bkColour);
  1662.   PCanvasState::SetFillFgColour(bkColour);
  1663.   PCanvasState::SetFillBkColour(fgColour);
  1664.   PCanvasState::SetTextFgColour(fgColour);
  1665.   PCanvasState::SetTextBkColour(bkColour);
  1666.   PCanvasState::SetFont(interactor->GetFont());
  1667. }
  1668. void PInteractorCanvas::Scroll(PORDINATE dx, PORDINATE dy)
  1669. {
  1670.   Scroll(dx, dy, GetDrawingBounds());
  1671. }
  1672. void PInteractorCanvas::Scroll(const PPoint & amt)
  1673. {
  1674.   Scroll(amt.X(), amt.Y(), GetDrawingBounds());
  1675. }
  1676. void PInteractorCanvas::Scroll(const PPoint & amt, const PRect & rect)
  1677. {
  1678.   Scroll(amt.X(), amt.Y(), rect);
  1679. }
  1680. #endif
  1681. //////////////////////////////////////////////////////////////////////////////
  1682. // PMemoryCanvas
  1683. PRect PMemoryCanvas::GetDrawingBounds() const
  1684. {
  1685.   return FromPixels(PRect(0, 0, image->Width(), image->Height()));
  1686. }
  1687. #undef new
  1688. // End Of File ///////////////////////////////////////////////////////////////