00001 // $Id: maskedrr.cpp 1288 2006-06-09 13:16:24Z phil $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 // The Masked Render region 00099 00100 /* 00101 */ 00102 00103 #include "camtypes.h" 00104 #include "maskedrr.h" 00105 //#include "doccolor.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00106 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00107 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00108 #include "nodebmp.h" 00109 //#include "view.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 00111 // An implement to match the Declare in the .h file. 00112 CC_IMPLEMENT_DYNAMIC(MaskedRenderRegion, GRenderBitmap) 00113 00114 // This will get Camelot to display the filename and linenumber of any memory allocations 00115 // that are not released at program exit 00116 #define new CAM_DEBUG_NEW 00117 00118 00119 // This table holds the number of bits set for each of the byte values 0 to 255. This table is 00120 // used to help speed up the counting of the number of set pixels in the mask 00121 INT32 MaskedRenderRegion::BitCountTable[256] = 00122 { 00123 0, /* 0x0 */ 1, /* 0x1 */ 1, /* 0x2 */ 2, /* 0x3 */ 1, /* 0x4 */ 00124 2, /* 0x5 */ 2, /* 0x6 */ 3, /* 0x7 */ 1, /* 0x8 */ 2, /* 0x9 */ 00125 2, /* 0xA */ 3, /* 0xB */ 2, /* 0xC */ 3, /* 0xD */ 3, /* 0xE */ 00126 4, /* 0xF */ 1, /* 0x10 */ 2, /* 0x11 */ 2, /* 0x12 */ 3, /* 0x13 */ 00127 2, /* 0x14 */ 3, /* 0x15 */ 3, /* 0x16 */ 4, /* 0x17 */ 2, /* 0x18 */ 00128 3, /* 0x19 */ 3, /* 0x1A */ 4, /* 0x1B */ 3, /* 0x1C */ 4, /* 0x1D */ 00129 4, /* 0x1E */ 5, /* 0x1F */ 1, /* 0x20 */ 2, /* 0x21 */ 2, /* 0x22 */ 00130 3, /* 0x23 */ 2, /* 0x24 */ 3, /* 0x25 */ 3, /* 0x26 */ 4, /* 0x27 */ 00131 2, /* 0x28 */ 3, /* 0x29 */ 3, /* 0x2A */ 4, /* 0x2B */ 3, /* 0x2C */ 00132 4, /* 0x2D */ 4, /* 0x2E */ 5, /* 0x2F */ 2, /* 0x30 */ 3, /* 0x31 */ 00133 3, /* 0x32 */ 4, /* 0x33 */ 3, /* 0x34 */ 4, /* 0x35 */ 4, /* 0x36 */ 00134 5, /* 0x37 */ 3, /* 0x38 */ 4, /* 0x39 */ 4, /* 0x3A */ 5, /* 0x3B */ 00135 4, /* 0x3C */ 5, /* 0x3D */ 5, /* 0x3E */ 6, /* 0x3F */ 1, /* 0x40 */ 00136 2, /* 0x41 */ 2, /* 0x42 */ 3, /* 0x43 */ 2, /* 0x44 */ 3, /* 0x45 */ 00137 3, /* 0x46 */ 4, /* 0x47 */ 2, /* 0x48 */ 3, /* 0x49 */ 3, /* 0x4A */ 00138 4, /* 0x4B */ 3, /* 0x4C */ 4, /* 0x4D */ 4, /* 0x4E */ 5, /* 0x4F */ 00139 2, /* 0x50 */ 3, /* 0x51 */ 3, /* 0x52 */ 4, /* 0x53 */ 3, /* 0x54 */ 00140 4, /* 0x55 */ 4, /* 0x56 */ 5, /* 0x57 */ 3, /* 0x58 */ 4, /* 0x59 */ 00141 4, /* 0x5A */ 5, /* 0x5B */ 4, /* 0x5C */ 5, /* 0x5D */ 5, /* 0x5E */ 00142 6, /* 0x5F */ 2, /* 0x60 */ 3, /* 0x61 */ 3, /* 0x62 */ 4, /* 0x63 */ 00143 3, /* 0x64 */ 4, /* 0x65 */ 4, /* 0x66 */ 5, /* 0x67 */ 3, /* 0x68 */ 00144 4, /* 0x69 */ 4, /* 0x6A */ 5, /* 0x6B */ 4, /* 0x6C */ 5, /* 0x6D */ 00145 5, /* 0x6E */ 6, /* 0x6F */ 3, /* 0x70 */ 4, /* 0x71 */ 4, /* 0x72 */ 00146 5, /* 0x73 */ 4, /* 0x74 */ 5, /* 0x75 */ 5, /* 0x76 */ 6, /* 0x77 */ 00147 4, /* 0x78 */ 5, /* 0x79 */ 5, /* 0x7A */ 6, /* 0x7B */ 5, /* 0x7C */ 00148 6, /* 0x7D */ 6, /* 0x7E */ 7, /* 0x7F */ 1, /* 0x80 */ 2, /* 0x81 */ 00149 2, /* 0x82 */ 3, /* 0x83 */ 2, /* 0x84 */ 3, /* 0x85 */ 3, /* 0x86 */ 00150 4, /* 0x87 */ 2, /* 0x88 */ 3, /* 0x89 */ 3, /* 0x8A */ 4, /* 0x8B */ 00151 3, /* 0x8C */ 4, /* 0x8D */ 4, /* 0x8E */ 5, /* 0x8F */ 2, /* 0x90 */ 00152 3, /* 0x91 */ 3, /* 0x92 */ 4, /* 0x93 */ 3, /* 0x94 */ 4, /* 0x95 */ 00153 4, /* 0x96 */ 5, /* 0x97 */ 3, /* 0x98 */ 4, /* 0x99 */ 4, /* 0x9A */ 00154 5, /* 0x9B */ 4, /* 0x9C */ 5, /* 0x9D */ 5, /* 0x9E */ 6, /* 0x9F */ 00155 2, /* 0xA0 */ 3, /* 0xA1 */ 3, /* 0xA2 */ 4, /* 0xA3 */ 3, /* 0xA4 */ 00156 4, /* 0xA5 */ 4, /* 0xA6 */ 5, /* 0xA7 */ 3, /* 0xA8 */ 4, /* 0xA9 */ 00157 4, /* 0xAA */ 5, /* 0xAB */ 4, /* 0xAC */ 5, /* 0xAD */ 5, /* 0xAE */ 00158 6, /* 0xAF */ 3, /* 0xB0 */ 4, /* 0xB1 */ 4, /* 0xB2 */ 5, /* 0xB3 */ 00159 4, /* 0xB4 */ 5, /* 0xB5 */ 5, /* 0xB6 */ 6, /* 0xB7 */ 4, /* 0xB8 */ 00160 5, /* 0xB9 */ 5, /* 0xBA */ 6, /* 0xBB */ 5, /* 0xBC */ 6, /* 0xBD */ 00161 6, /* 0xBE */ 7, /* 0xBF */ 2, /* 0xC0 */ 3, /* 0xC1 */ 3, /* 0xC2 */ 00162 4, /* 0xC3 */ 3, /* 0xC4 */ 4, /* 0xC5 */ 4, /* 0xC6 */ 5, /* 0xC7 */ 00163 3, /* 0xC8 */ 4, /* 0xC9 */ 4, /* 0xCA */ 5, /* 0xCB */ 4, /* 0xCC */ 00164 5, /* 0xCD */ 5, /* 0xCE */ 6, /* 0xCF */ 3, /* 0xD0 */ 4, /* 0xD1 */ 00165 4, /* 0xD2 */ 5, /* 0xD3 */ 4, /* 0xD4 */ 5, /* 0xD5 */ 5, /* 0xD6 */ 00166 6, /* 0xD7 */ 4, /* 0xD8 */ 5, /* 0xD9 */ 5, /* 0xDA */ 6, /* 0xDB */ 00167 5, /* 0xDC */ 6, /* 0xDD */ 6, /* 0xDE */ 7, /* 0xDF */ 3, /* 0xE0 */ 00168 4, /* 0xE1 */ 4, /* 0xE2 */ 5, /* 0xE3 */ 4, /* 0xE4 */ 5, /* 0xE5 */ 00169 5, /* 0xE6 */ 6, /* 0xE7 */ 4, /* 0xE8 */ 5, /* 0xE9 */ 5, /* 0xEA */ 00170 6, /* 0xEB */ 5, /* 0xEC */ 6, /* 0xED */ 6, /* 0xEE */ 7, /* 0xEF */ 00171 4, /* 0xF0 */ 5, /* 0xF1 */ 5, /* 0xF2 */ 6, /* 0xF3 */ 5, /* 0xF4 */ 00172 6, /* 0xF5 */ 6, /* 0xF6 */ 7, /* 0xF7 */ 5, /* 0xF8 */ 6, /* 0xF9 */ 00173 6, /* 0xFA */ 7, /* 0xFB */ 6, /* 0xFC */ 7, /* 0xFD */ 7, /* 0xFE */ 00174 8 /* 0xFF */ 00175 }; 00176 00177 00178 00179 00180 /******************************************************************************************** 00181 00182 > MaskedRenderRegion::MaskedRenderRegion( DocRect ClipRegion, Matrix ConvertMatrix, 00183 FIXED16 ViewScale, UINT32 Depth, double dpi) 00184 00185 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00186 Created: 11/4/95 00187 Inputs: ClipRect - the Clipping rectangle 00188 ConvertMatrix - the Matrix to render through 00189 ViewScale - The Scale Factor 00190 dpi - Dots per inch 00191 Purpose: Constructor. Sends everything on to the base class. 00192 INT32 dpi changed to FIXED16 dpi (12/12/95) to improve the range of values allowed 00193 at the < 1000dpi settings that we will be using. 00194 00195 ********************************************************************************************/ 00196 00197 MaskedRenderRegion::MaskedRenderRegion( DocRect ClipRegion, Matrix ConvertMatrix, 00198 FIXED16 ViewScale, double dpi) 00199 : GRenderBitmap(ClipRegion, ConvertMatrix, ViewScale, 1, dpi) 00200 { 00201 // Some attrs we use. NULL by default 00202 pFillAttr = NULL; 00203 pStrokeAttr = NULL; 00204 Black = DocColour(0,0,0); 00205 White = DocColour(255,255,255); 00206 } 00207 00208 00209 /******************************************************************************************** 00210 00211 > MaskedRenderRegion::~MaskedRenderRegion() 00212 00213 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00214 Created: 11/4/95 00215 Purpose: Default destructor 00216 00217 ********************************************************************************************/ 00218 00219 MaskedRenderRegion::~MaskedRenderRegion() 00220 { 00221 // Kill the fill attr 00222 if (pFillAttr!=NULL) 00223 { 00224 delete pFillAttr; 00225 pFillAttr = NULL; 00226 } 00227 00228 // kill the stroke attr 00229 if (pStrokeAttr!=NULL) 00230 { 00231 delete pStrokeAttr; 00232 pStrokeAttr = NULL; 00233 } 00234 } 00235 00236 00237 /******************************************************************************************** 00238 00239 > BOOL MaskedRenderRegion::StartRender() 00240 00241 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00242 Created: 20/4/95 00243 Returns: TRUE if it worked, FALSE if it failed 00244 Purpose: Starts the render region up. This version just calls the base class and 00245 allocates a couple of attributes used during the rendering. 00246 00247 ********************************************************************************************/ 00248 00249 BOOL MaskedRenderRegion::StartRender() 00250 { 00251 // Call the base class 00252 if (!GRenderBitmap::StartRender()) 00253 return FALSE; 00254 00255 // If we got a bitmap, then clear it 00256 if (pBits!=NULL && pBitmapInfo!=NULL) 00257 { 00258 // Find out how many bytes there are to look at 00259 INT32 TotalBytes = pBitmapInfo->bmiHeader.biSizeImage; 00260 00261 // clear it all out - a Set pixels is transparent, an Unset pixel is not 00262 memset(pBits, 0xFF, TotalBytes); 00263 } 00264 00265 // Do our own thing - We need some attrs 00266 if (pFillAttr==NULL) 00267 pFillAttr = new FlatTranspFillAttribute(0); 00268 00269 if (pStrokeAttr==NULL) 00270 pStrokeAttr = new StrokeTranspAttribute(0); 00271 00272 // See if we got the ram we wanted 00273 if ((pFillAttr==NULL) || (pStrokeAttr==NULL)) 00274 return FALSE; 00275 00276 // if we get here, everything has worked 00277 return TRUE; 00278 } 00279 00280 00281 00282 /******************************************************************************************** 00283 00284 > void MaskedRenderRegion::SetHostCaps(RenderCaps* pCaps) 00285 00286 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00287 Created: 24/4/95 00288 Inputs: pCaps - pointer to the render caps for the host render region 00289 Purpose: Tells the mask region what attributes are considered complex. 00290 00291 ********************************************************************************************/ 00292 00293 void MaskedRenderRegion::SetHostCaps(RRCaps* pCaps) 00294 { 00295 // Make a copy of the host regions caps 00296 HostCaps = *pCaps; 00297 } 00298 00299 00300 00301 /******************************************************************************************** 00302 00303 > virtual void MaskedRenderRegion::DrawPathToOutputDevice(Path* pPath) 00304 00305 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00306 Created: 24/4/95 00307 Inputs: pPath - The path that needs rendering 00308 Purpose: Renders the path into the mask. It makes sure that all the attributes are 00309 set up correctly first though 00310 00311 ********************************************************************************************/ 00312 00313 void MaskedRenderRegion::DrawPathToOutputDevice(Path* pPath, PathShape) 00314 { 00315 // Save the context 00316 SaveContext(); 00317 00318 BOOL RenderFill = FALSE; 00319 00320 // Get the current fill attr 00321 FillGeometryAttribute* pFillAttr = (FillGeometryAttribute*) CurrentAttrs[ATTR_FILLGEOMETRY].pAttr; 00322 00323 if (pFillAttr->GetBitmap() != NULL && pFillAttr->GetBitmap()->GetBPP() <= 8) 00324 { 00325 INT32 TranspIndex; 00326 00327 // If it's a masked bitmap fill, then we'll need to actually render it 00328 // (but we'll force all the non-masked pixels to be rendered black) 00329 if (pFillAttr->GetBitmap()->GetTransparencyIndex(&TranspIndex)) 00330 RenderFill = TRUE; 00331 } 00332 00333 if (RenderFill) 00334 { 00335 BOOL OldVMState = RenderFlags.VeryMono; 00336 RenderFlags.VeryMono = TRUE; // Forces non-masked pixels to be plotted black 00337 00338 // Draw the path, with the bitmap fill 00339 GRenderBitmap::DrawPathToOutputDevice(pPath); 00340 00341 RenderFlags.VeryMono = OldVMState; 00342 } 00343 else 00344 { 00345 // Does this shape make use of complex things 00346 if (TestForComplexShape(&HostCaps)) 00347 SetNextShapeColour(Black); 00348 else 00349 SetNextShapeColour(White); 00350 00351 // Draw the path 00352 GRenderBitmap::DrawPathToOutputDevice(pPath); 00353 } 00354 00355 // restore the context 00356 RestoreContext(); 00357 } 00358 00359 00360 /******************************************************************************************** 00361 00362 > virtual void MaskedRenderRegion::DrawRect(DocRect* pRectToRender) 00363 00364 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00365 Created: 6/4/95 00366 Inputs: pRectToRender - The Rectangle that we need to render 00367 Purpose: This function will examine the attributes etc to see if this represents a 00368 simple or compex shape. It will set up the attributes according to the result 00369 of this and then call the base class version of the function. 00370 00371 ********************************************************************************************/ 00372 00373 void MaskedRenderRegion::DrawRect(DocRect* pRectToRender) 00374 { 00375 // Save the context 00376 SaveContext(); 00377 00378 // Does this shape make use of complex things 00379 if (TestForComplexShape(&HostCaps)) 00380 SetNextShapeColour(Black); 00381 else 00382 SetNextShapeColour(White); 00383 00384 // Draw the path 00385 GRenderBitmap::DrawRect(pRectToRender); 00386 00387 // restore the context 00388 RestoreContext(); 00389 } 00390 00391 00392 /******************************************************************************************** 00393 00394 > virtual void MaskedRenderRegion::DrawLine(const DocCoord &StartPoint, 00395 const DocCoord &EndPoint) 00396 00397 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00398 Created: 6/4/95 00399 Inputs: StartPoint, EndPoint - the coords to draw a line between 00400 Purpose: This function will examine the attributes etc to see if this represents a 00401 simple or compex shape. It will set up the attributes according to the result 00402 of this and then call the base class version of the function. 00403 00404 ********************************************************************************************/ 00405 00406 void MaskedRenderRegion::DrawLine(const DocCoord &StartPoint, const DocCoord &EndPoint) 00407 { 00408 // Save the context 00409 SaveContext(); 00410 00411 // Does this shape make use of complex things 00412 if (TestForComplexShape(&HostCaps)) 00413 SetNextShapeColour(Black); 00414 else 00415 SetNextShapeColour(White); 00416 00417 // Draw the path 00418 GRenderBitmap::DrawLine(StartPoint, EndPoint); 00419 00420 // restore the context 00421 RestoreContext(); 00422 } 00423 00424 00425 /******************************************************************************************** 00426 00427 > virtual void MaskedRenderRegion::DrawPixel(const DocCoord &Point) 00428 00429 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00430 Created: 6/4/95 00431 Inputs: Point - the coord to draw the pixel in 00432 Purpose: This function will examine the attributes etc to see if this represents a 00433 simple or compex shape. It will set up the attributes according to the result 00434 of this and then call the base class version of the function. 00435 00436 ********************************************************************************************/ 00437 00438 void MaskedRenderRegion::DrawPixel(const DocCoord &Point) 00439 { 00440 // Save the context 00441 SaveContext(); 00442 00443 // Does this shape make use of complex things 00444 if (TestForComplexShape(&HostCaps)) 00445 SetNextShapeColour(Black); 00446 else 00447 SetNextShapeColour(White); 00448 00449 // Draw the path 00450 GRenderBitmap::DrawPixel(Point); 00451 00452 // restore the context 00453 RestoreContext(); 00454 } 00455 00456 00457 /******************************************************************************************** 00458 00459 > virtual void MaskedRenderRegion::DrawBitmap(const DocCoord &Point, KernelBitmap* pBitmap) 00460 00461 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00462 Created: 6/4/95 00463 Inputs: Point - The position to draw the bitmap at 00464 pBitmap - the bitmap that needs drawing 00465 Purpose: This function will examine the attributes etc to see if this represents a 00466 simple or compex shape. It will set up the attributes according to the result 00467 of this and then call the base class version of the function. 00468 00469 ********************************************************************************************/ 00470 00471 void MaskedRenderRegion::DrawBitmap(const DocCoord &Point, KernelBitmap* pBitmap) 00472 { 00473 // Save the context 00474 SaveContext(); 00475 00476 // Does this shape make use of complex things 00477 if (TestForComplexShape(&HostCaps)) 00478 SetNextShapeColour(Black); 00479 else 00480 SetNextShapeColour(White); 00481 00482 // Draw the path 00483 GRenderBitmap::DrawBitmap(Point, pBitmap); 00484 00485 // restore the context 00486 RestoreContext(); 00487 } 00488 00489 00490 /******************************************************************************************** 00491 00492 > virtual void MaskedRenderRegion::DrawBitmap(const DocCoord &Point, UINT32 BitmapID, 00493 UINT32 ToolID) 00494 00495 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00496 Created: 6/4/95 00497 Inputs: Point - the position to draw the bitmap at 00498 BitmapID - The ID of the bitmap to render 00499 ToolID - the ID of the tool that the bitmap belongs to 00500 Purpose: This function will examine the attributes etc to see if this represents a 00501 simple or compex shape. It will set up the attributes according to the result 00502 of this and then call the base class version of the function. 00503 00504 ********************************************************************************************/ 00505 00506 void MaskedRenderRegion::DrawBitmap(const DocCoord &Point, UINT32 BitmapID, UINT32 ToolID) 00507 { 00508 // Save the context 00509 SaveContext(); 00510 00511 // Does this shape make use of complex things 00512 if (TestForComplexShape(&HostCaps)) 00513 SetNextShapeColour(Black); 00514 else 00515 SetNextShapeColour(White); 00516 00517 // Draw the path 00518 GRenderBitmap::DrawBitmap(Point, BitmapID, ToolID); 00519 00520 // restore the context 00521 RestoreContext(); 00522 } 00523 00524 BOOL MaskedRenderRegion::DrawTransformedBitmap(NodeBitmap *pNodeBitmap) 00525 { 00526 // Save the context 00527 SaveContext(); 00528 00529 // Work out if we can do this bitmap directly 00530 BOOL CanDoBitmap = FALSE; 00531 00532 // Does this shape make use of complex things 00533 if (!(TestForComplexShape(&HostCaps) || pNodeBitmap->NeedsTransparency())) 00534 { 00535 // See what kind of bitmaps this render region can do 00536 if (HostCaps.ArbitraryBitmaps) 00537 { 00538 // We can do anything... 00539 CanDoBitmap = TRUE; 00540 } 00541 else 00542 { 00543 if (HostCaps.SimpleBitmaps) 00544 { 00545 // Check that the bitmap area is rectangular, and is perpendicular to 00546 // the x and y axes. 00547 if (pNodeBitmap->HasSimpleOrientation(this)) 00548 { 00549 // Yes - simple scaling - the render region can do this. 00550 CanDoBitmap = TRUE; 00551 } 00552 } 00553 } 00554 } 00555 00556 // Here we set up reasonable attributes - we want to fill the bitmap 00557 // path but not stroke it. NB. This is very important - do not remove 00558 // otherwise the mask will be wrong! 00559 DocColour colorBlack( COLOUR_BLACK ); 00560 SetFillColour( colorBlack ); 00561 DocColour colorNone( COLOUR_NONE ); 00562 SetLineColour( colorNone ); 00563 00564 if (CanDoBitmap) 00565 { 00566 SetNextShapeColour(White); 00567 00568 // Draw the path (that represents the bitmap object) 00569 GRenderBitmap::DrawPathToOutputDevice(&pNodeBitmap->InkPath); 00570 } 00571 else 00572 { 00573 if (pNodeBitmap->NeedsTransparency()) 00574 { 00575 // It's a masked bitmap, so we'll need to actually render the non-masked 00576 // pixels as black 00577 BOOL OldVMState = RenderFlags.VeryMono; 00578 RenderFlags.VeryMono = TRUE; // Forces non-masked pixels to be plotted black 00579 00580 // Call base class to plot the bitmap 00581 RenderRegion::DrawTransformedBitmap(pNodeBitmap); 00582 00583 RenderFlags.VeryMono = OldVMState; 00584 } 00585 else 00586 { 00587 SetNextShapeColour(Black); 00588 00589 // Draw the path (that represents the bitmap object) 00590 GRenderBitmap::DrawPathToOutputDevice(&pNodeBitmap->InkPath); 00591 } 00592 } 00593 00594 // restore the context 00595 RestoreContext(); 00596 00597 return TRUE; 00598 } 00599 00600 /******************************************************************************************** 00601 00602 > virtual void MaskedRenderRegion::DrawDragRect(DocRect *RectToRender) 00603 00604 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00605 Created: 6/4/95 00606 Inputs: RectToRender - The Rectangle 00607 Purpose: None - Does nothing 00608 00609 ********************************************************************************************/ 00610 00611 void MaskedRenderRegion::DrawDragRect(DocRect *RectToRender) 00612 { 00613 } 00614 00615 00616 /******************************************************************************************** 00617 00618 > virtual void MaskedRenderRegion::DrawBlob(DocCoord p, BlobType type) 00619 00620 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00621 Created: 6/4/95 00622 Inputs: p - A coord 00623 type - The type of blob 00624 Purpose: None - Does nothing 00625 00626 ********************************************************************************************/ 00627 00628 void MaskedRenderRegion::DrawBlob(DocCoord p, BlobType type) 00629 { 00630 } 00631 00632 00633 /******************************************************************************************** 00634 00635 > virtual void MaskedRenderRegion::DrawCross(const DocCoord &Point, const UINT32 Size) 00636 00637 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00638 Created: 6/4/95 00639 Inputs: Point - a Coord 00640 Size - the size of the cross 00641 Purpose: None - Does nothing 00642 00643 ********************************************************************************************/ 00644 00645 void MaskedRenderRegion::DrawCross(const DocCoord &Point, const UINT32 Size) 00646 { 00647 } 00648 00649 00650 /******************************************************************************************** 00651 00652 > virtual void MaskedRenderRegion::DrawBitmapBlob(const DocCoord &Point, 00653 KernelBitmap* BlobShape) 00654 00655 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00656 Created: 6/4/95 00657 Inputs: Point - A Coord 00658 BlobShape - the bitmap to use 00659 Purpose: None - Does nothing 00660 00661 ********************************************************************************************/ 00662 00663 void MaskedRenderRegion::DrawBitmapBlob(const DocCoord &Point, KernelBitmap* BlobShape) 00664 { 00665 } 00666 00667 00668 /******************************************************************************************** 00669 00670 > virtual void MaskedRenderRegion::DrawBitmapBlob(const DocCoord &Point, UINT32 BitmapID, 00671 UINT32 ToolID) 00672 00673 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00674 Created: 6/4/95 00675 Inputs: Point - A coord 00676 BitmapID - the ID of a bitmap 00677 ToolID - the Id of the tool the bitmap resource is in 00678 Purpose: None - Does nothing 00679 00680 ********************************************************************************************/ 00681 00682 void MaskedRenderRegion::DrawBitmapBlob(const DocCoord &Point, ResourceID resID ) 00683 { 00684 } 00685 00686 00687 00688 00689 00690 /******************************************************************************************** 00691 00692 > void MaskedRenderRegion::SetNextShapeColour(DocColour& RequiredCol) 00693 00694 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00695 Created: 20/4/95 00696 Inputs: RequiredCol - The colour to replace fill and stroke colours with 00697 Purpose: Sets all the attributes up so that we can render into our mask. It will 00698 boil everything down to a flat fill and stroke ready to be rendered into 00699 the mask. The colour passed in will probably be Black or White, but I left 00700 it open in case I thought of some other use for this. 00701 00702 ********************************************************************************************/ 00703 00704 void MaskedRenderRegion::SetNextShapeColour(DocColour& RequiredCol) 00705 { 00706 // Find out about the fill attr 00707 ColourFillAttribute* pColFillAttr = (ColourFillAttribute*) CurrentAttrs[ATTR_FILLGEOMETRY].pAttr; 00708 if ((pColFillAttr!=NULL) && (pColFillAttr->IS_KIND_OF(GradFillAttribute))) 00709 { 00710 // This is a grad fill, so just set the colour as required 00711 SetFillColour(RequiredCol); 00712 } 00713 else 00714 { 00715 // Is there a fill colour of any kind 00716 DocColour MyFillColour = RR_FILLCOLOUR(); 00717 00718 // See if it is 'no colour' 00719 if (!MyFillColour.IsTransparent()) 00720 { 00721 // Nope, its a real colour alright, so we had better set the fill colour 00722 SetFillColour(RequiredCol); 00723 } 00724 } 00725 00726 // Find out about the line colour 00727 DocColour MyStrokeColour = RR_STROKECOLOUR(); 00728 00729 // See if it is 'no colour' 00730 if (!MyStrokeColour.IsTransparent()) 00731 { 00732 // Nope, its a real colour alright, so we had better set the fill colour 00733 SetLineColour(RequiredCol); 00734 } 00735 00736 // Set Fill transp to none 00737 if (pFillAttr!=NULL) 00738 RenderRegion::SetTranspFillGeometry(pFillAttr, FALSE); 00739 00740 // Set the stroke transp to none 00741 if (pStrokeAttr!=NULL) 00742 RenderRegion::SetLineTransp(pStrokeAttr, FALSE); 00743 } 00744 00745 00746 00747 00748 /******************************************************************************************** 00749 00750 > BOOL MaskedRenderRegion::SpreadMask() 00751 00752 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00753 Created: 15/5/95 00754 Returns: TRUE if the mask was spread, FALSE if there was no mask in the first place 00755 Purpose: Spreads the mask out by a pixel. This allows us to make the area that is 00756 blitted slightly bigger to cover up any differences between the device 00757 resolution and the bitmap resolution. This function will grow the mask 00758 above, below, to the left and right by a single pixel. If this is not 00759 enough, call this function more than once. 00760 00761 ********************************************************************************************/ 00762 00763 BOOL MaskedRenderRegion::SpreadMask() 00764 { 00765 // If there is a bitmap 00766 if (pBits!=NULL && pBitmapInfo!=NULL) 00767 { 00768 // Get the scan line size in bytes 00769 INT32 ScanLineByteSize = (pBitmapInfo->bmiHeader.biWidth+7)/8; 00770 00771 // Round it up to the nearest word boundary. Note, this is still a count of bytes 00772 INT32 ScanLineWordSize = ((ScanLineByteSize+3)/4)*4; 00773 00774 // Start looping through all the scan lines in the mask, 00775 // going from top to bottom, moving set pixels up 00776 LPBYTE CurrentByte = NULL; 00777 LPBYTE ByteAbove = NULL; 00778 INT32 i; 00779 for (i=1; i<pBitmapInfo->bmiHeader.biHeight; i++) 00780 { 00781 // point CurrentByte at the start of the next scan line 00782 CurrentByte = pBits + (i*ScanLineWordSize); 00783 ByteAbove = pBits + ((i-1)*ScanLineWordSize); 00784 00785 // Go along the scan line 00786 BOOL SetHighBit = FALSE; 00787 for (INT32 j=0; j<ScanLineByteSize; j++) 00788 { 00789 // Try and set the leading pixel on the current byte 00790 BYTE Mask = 0x01; 00791 BYTE Current = BYTE(~(*CurrentByte)); 00792 00793 // Loop though the mask 00794 BOOL Found = FALSE; 00795 while (Mask!=0) 00796 { 00797 // See if we have found the least sig. pixel yet 00798 if ((Mask & Current) != 0) 00799 { 00800 Found = TRUE; 00801 break; 00802 } 00803 00804 // Move the mask along a bit 00805 Mask = Mask << 1; 00806 } 00807 00808 // Set the high bit if needed 00809 if (SetHighBit) 00810 { 00811 Current = Current | 0x80; 00812 SetHighBit = FALSE; 00813 } 00814 00815 // If we found a bit in this byte, set the bit next to the least sig bit 00816 if (Found) 00817 { 00818 if (Mask==0x01) 00819 SetHighBit = TRUE; 00820 else 00821 Current = Current | (Mask>>1); 00822 } 00823 00824 // Or this byte with the one in the scan line above 00825 BYTE Result = BYTE(~(*ByteAbove)) | Current; 00826 *ByteAbove = BYTE(~Result); 00827 00828 // Move to the next byte 00829 CurrentByte++; 00830 ByteAbove++; 00831 } 00832 } 00833 00834 // Start looping through all the scan lines in the mask, 00835 // going from bottom to top, moving set pixels down 00836 CurrentByte = NULL; 00837 LPBYTE ByteBelow = NULL; 00838 for (i=pBitmapInfo->bmiHeader.biHeight-2; i>=0; i--) 00839 { 00840 // point CurrentByte at the start of the next scan line 00841 CurrentByte = pBits + (i*ScanLineWordSize) + ScanLineByteSize; 00842 ByteBelow = pBits + ((i+1)*ScanLineWordSize) + ScanLineByteSize; 00843 00844 // Go along the scan line 00845 BOOL SetLowBit = FALSE; 00846 for (INT32 j=ScanLineByteSize-1; j>=0; j--) 00847 { 00848 // Try and set the leading pixel on the current byte 00849 BYTE Mask = 0x80; 00850 BYTE Current = BYTE(~(*CurrentByte)); 00851 00852 // loop though the mask 00853 BOOL Found = FALSE; 00854 while (Mask!=0) 00855 { 00856 // See if we have found the least sig. pixel yet 00857 if ((Mask & Current) != 0) 00858 { 00859 Found = TRUE; 00860 break; 00861 } 00862 00863 // Move the mask along a bit 00864 Mask = Mask >> 1; 00865 } 00866 00867 // Set the low bit if needed 00868 if (SetLowBit) 00869 { 00870 Current = Current | 0x01; 00871 SetLowBit = FALSE; 00872 } 00873 00874 // If we found a bit in this byte, set the bit next to the most sig bit 00875 if (Found) 00876 { 00877 if (Mask==0x80) 00878 SetLowBit = TRUE; 00879 else 00880 Current = Current | (Mask<<1); 00881 } 00882 00883 // Or this byte with the one in the scan line below 00884 BYTE Result = BYTE(~(*ByteBelow)) | Current; 00885 *ByteBelow = BYTE(~Result); 00886 00887 // Move to the next byte 00888 CurrentByte--; 00889 ByteBelow--; 00890 } 00891 } 00892 } 00893 00894 return TRUE; 00895 } 00896 00897 00898 /******************************************************************************************** 00899 00900 > INT32 MaskedRenderRegion::FindCoverage(BOOL AnyCoverageReturns100 = FALSE) 00901 00902 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 00903 Created: 21/4/95 00904 00905 Inputs: AnyConverageReturns100 - In most (if not all) calls to this function, 00906 the caller is only interested in whether coverage is equal to zero 00907 or not (i.e. "Do I have to bother rendering anything?"). If you set 00908 this flag to TRUE, this function will return 100% immediately if it 00909 finds a single pixel set in the mask, or 0% only if there are no pixels 00910 set in the mask. This is thus a much faster test of "do we need to render" 00911 because it usually doesn't have to scan far before it finds a pixel to plot. 00912 (Added by Jason, 1/7/96) 00913 00914 Returns: 0 - 100. This represents the percentage of the masked bitmap that has pixels 00915 set in it. A value of 0 means that there are no pixels set in the mask. You 00916 can take this value to mean 'do not bother trying to display the bitmap cos 00917 none of it is visible'. A value of 100 means that every pixel in the mask is set 00918 so no clever masked plotting of the bitmap is required. 00919 (or, if the AnyConverageReturns100 flag was set, a value of 100 just means 00920 that there was at least one pixel requiring plotting) 00921 00922 Purpose: Finds out how much of the mask has been set. 00923 00924 ********************************************************************************************/ 00925 00926 INT32 MaskedRenderRegion::FindCoverage(BOOL AnyCoverageReturns100) 00927 { 00928 INT32 TotalPixels = 0; 00929 INT32 TotalClearPixels = 0; 00930 00931 if (pBits!=NULL && pBitmapInfo!=NULL) 00932 { 00933 // Get the scan line size in bytes 00934 const INT32 ScanLineByteSize = (pBitmapInfo->bmiHeader.biWidth+7)/8; 00935 00936 // Round it up to the nearest word boundary. Note, this is still a count of bytes 00937 const INT32 ScanLineWordSize = ((ScanLineByteSize+3)/4)*4; 00938 00939 // Work out how many padding pixels (bits) are on the end of the scanline 00940 const INT32 EndPixels = 8- ((ScanLineByteSize*8) - pBitmapInfo->bmiHeader.biWidth); 00941 00942 // The last byte of each scanline may not use all its pixels, so we build a mask, 00943 // which is used to discount padding pixels from consideration 00944 BYTE Mask = 0x0; 00945 { 00946 BYTE Bit = 0x80; 00947 for (INT32 i=0; i<EndPixels; i++) 00948 Mask |= Bit>>i; 00949 } 00950 00951 00952 // Start looping through all the scan lines in the mask 00953 LPBYTE CurrentByte = NULL; 00954 for (INT32 i=0; i<pBitmapInfo->bmiHeader.biHeight; i++) 00955 { 00956 // point CurrentByte at the start of the next scan line 00957 CurrentByte = pBits + (i*ScanLineWordSize); 00958 00959 // Count this scan line of pixels 00960 TotalPixels += pBitmapInfo->bmiHeader.biWidth; 00961 00962 // Go along the scan line, counting pixels 00963 for (INT32 j=0; j<ScanLineByteSize-1; j++) 00964 { 00965 // look up the current byte 00966 TotalClearPixels += BitCountTable[*CurrentByte]; 00967 00968 // Move to the next byte 00969 CurrentByte ++; 00970 } 00971 00972 BYTE EndByte = *CurrentByte & Mask; 00973 TotalClearPixels += BitCountTable[EndByte]; 00974 00975 // If we just want to know if the entire mask is clear, then check if we found 00976 // any non-masked pixels at all in this scanline - if so, return immediately. 00977 if (AnyCoverageReturns100 && TotalClearPixels != TotalPixels) 00978 return(100); 00979 } 00980 } 00981 00982 // The mask was empty or missing 00983 if ((TotalClearPixels==TotalPixels) || (TotalPixels==0)) 00984 { 00985 TRACEUSER( "Rik", _T("Coverage = 0\n")); 00986 return 0; 00987 } 00988 00989 // Every pixel was set 00990 if (TotalClearPixels==0) 00991 { 00992 TRACEUSER( "Rik", _T("Coverage = 100\n")); 00993 return 100; 00994 } 00995 00996 // Work out the result 00997 INT32 Result = 100 - ((TotalClearPixels*100) / TotalPixels); 00998 00999 // Rounding errors could give this misleading result 01000 if (Result<=0) 01001 Result = 1; 01002 01003 // and this one, so change them 01004 if (Result>=100) 01005 Result = 99; 01006 01007 // Tell them what percentage of pixels were set 01008 TRACEUSER( "Rik", _T("Coverage = %ld\n"), Result); 01009 return Result; 01010 } 01011 01012 01013 01014 /******************************************************************************************** 01015 01016 > INT32 MaskedRenderRegion::FindMaskDpi() 01017 01018 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01019 Created: 30/4/95 01020 Returns: The Dpi of the mask in this region 01021 Purpose: This function is used to find out the DPI that the region was created at. 01022 This is important as the device it is displaying to may have a different 01023 dpi and the difference has to be compensated for. 01024 Returns a INT32 form of the dpi 01025 As most printing and masking related items only require non-fractional dpis 01026 then this should not be a problem. So return a rounded up form of the stored 01027 double form. 01028 01029 ********************************************************************************************/ 01030 01031 INT32 MaskedRenderRegion::FindMaskDpi() 01032 { 01033 // tell them about the dpi 01034 // Need to return a rounded form of the stored double dpi 01035 return (INT32)(PixelsPerInch + 0.5); 01036 } 01037 01038 /******************************************************************************************** 01039 01040 > double MaskedRenderRegion::FindMaskDpi() 01041 01042 Author: Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com> 01043 Created: 12/12/95 01044 Returns: The Dpi of the mask in this region 01045 Purpose: This function is used to find out the DPI that the region was created at. 01046 This is important as the device it is displaying to may have a different 01047 dpi and the difference has to be compensated for. 01048 Returns the new double form of the dpi 01049 01050 ********************************************************************************************/ 01051 01052 //double MaskedRenderRegion::FindMaskDpi() 01053 //{ 01054 // tell them about the dpi 01055 // return PixelsPerInch; 01056 //} 01057 01058 01059 /******************************************************************************************** 01060 01061 > void MaskedRenderRegion::GetFirstMaskRegion(MaskRegion* pMaskInfo) 01062 01063 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01064 Created: 21/4/95 01065 Outputs: pMaskInfo - holds info about the first region as output 01066 Purpose: This function finds the first scan line section in the mask that indicates 01067 pixels need to be set. When it finds the next section it fills in the info 01068 about it in pMaskInfo and returns. 01069 If there are no regions to be found in the mask then the Length member 01070 of pMaskInfo will be set to zero. This is your clue that there are no 01071 scan line sections to process. 01072 SeeAlso: MaskedRenderRegion::GetNextMaskRegion; struct MaskRegion 01073 01074 ********************************************************************************************/ 01075 01076 void MaskedRenderRegion::GetFirstMaskRegion(MaskRegion* pMaskInfo) 01077 { 01078 // Set up the starting conditions 01079 pMaskInfo->x = 0; 01080 pMaskInfo->y = 0; 01081 pMaskInfo->Length = 0; 01082 01083 // start looking for a bit we have to blit 01084 ScanMaskFrom(pMaskInfo); 01085 } 01086 01087 01088 01089 01090 /******************************************************************************************** 01091 01092 > void MaskedRenderRegion::GetNextMaskRegion(MaskRegion* pMaskInfo) 01093 01094 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01095 Created: 21/4/95 01096 Inputs: pMaskInfo - Holds info about the last region that was found 01097 Outputs: pMaskInfo - but holds info about the next region as output 01098 Purpose: This function finds the next scan line section in the mask that indicates 01099 pixels need to be set. It uses the info in the pMaskInfo param to work out 01100 where to start looking from. When it finds the next section, which could 01101 be on the same scan line as the present one, it fills in the info about it 01102 in pMaskInfo and returns. 01103 If there are no more regions to be found in the mask then the Length member 01104 of pMaskInfo will be set to zero. This is your clue that there are no more 01105 scan line sections to process. 01106 SeeAlso: MaskedRenderRegion::GetFirstMaskRegion; struct MaskRegion 01107 01108 ********************************************************************************************/ 01109 01110 void MaskedRenderRegion::GetNextMaskRegion(MaskRegion* pMaskInfo) 01111 { 01112 // Find the end of the last scan section 01113 // Move to the end of the last region 01114 pMaskInfo->x += pMaskInfo->Length; 01115 01116 // are we at the end of the scan line 01117 if (pMaskInfo->x >= pBitmapInfo->bmiHeader.biWidth) 01118 { 01119 pMaskInfo->x = 0; 01120 pMaskInfo->y++; 01121 } 01122 01123 // Reset the length to zero 01124 pMaskInfo->Length = 0; 01125 01126 // start looking for a bit we have to blit 01127 ScanMaskFrom(pMaskInfo); 01128 } 01129 01130 01131 01132 /******************************************************************************************** 01133 01134 > void MaskedRenderRegion::ScanMaskFrom(MaskRegion* pMaskInfo) 01135 01136 Author: Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com> 01137 Created: 23/4/95 01138 Inputs: pMaskInfo - Holds the position to start looking from 01139 Outputs: pMaskInfo - Hold info about the next scan section to look at 01140 Purpose: Searchs the mask for a section that means we will have to blit something. 01141 The starting position of the section and the length of the section are put 01142 into pMaskInfo and returned. pMaskInfo->Length will be set to zero if there 01143 are no more sections in the mask. 01144 01145 ********************************************************************************************/ 01146 01147 void MaskedRenderRegion::ScanMaskFrom(MaskRegion* pMaskInfo) 01148 { 01149 // Assume we will find no more scan sections 01150 pMaskInfo->Length = 0; 01151 01152 // get a mask to look along the bits in the mask 01153 INT32 Mask = 0x80; 01154 INT32 XStartPos = pMaskInfo->x; 01155 INT32 YStartPos = pMaskInfo->y; 01156 01157 // Set the mask up correctly, as the X starting pos may not be at the start of a byte 01158 if (XStartPos!=0) 01159 { 01160 // Go through the byte, setting the bits back to 1 as needed 01161 INT32 PixelNum = (XStartPos/8) * 8; 01162 while (PixelNum < XStartPos) 01163 { 01164 // Shift the bit along 01165 Mask = Mask>>1; 01166 01167 // Count the pixel 01168 PixelNum++; 01169 } 01170 } 01171 01172 // Find out how many bytes in a scan line 01173 INT32 ScanLineSize = (pBitmapInfo->bmiHeader.biWidth+7)/8; 01174 ScanLineSize = (ScanLineSize+3)&~3; 01175 01176 // We start out looking for the start of a region 01177 BOOL LookingForStart = TRUE; 01178 01179 // a pointer to the byte we are dealing with 01180 LPBYTE pByte = NULL; 01181 01182 // try and find the start of the first region 01183 for (INT32 j=YStartPos; j<pBitmapInfo->bmiHeader.biHeight; j++) 01184 { 01185 // Get the byte we are interested in 01186 pByte = pBits + (j*ScanLineSize) + (XStartPos/8); 01187 01188 // start going accross the scan line 01189 for (INT32 i=XStartPos; i<pBitmapInfo->bmiHeader.biWidth; i++) 01190 { 01191 // Find out what this bit is (1 or 0) 01192 INT32 ThisBit = (*pByte) & Mask; 01193 01194 // what are we looking for - the start or the end of a region. 01195 if (LookingForStart) 01196 { 01197 if (ThisBit == 0) 01198 { 01199 // Set the start position in the mask region 01200 pMaskInfo->x = i; 01201 pMaskInfo->y = j; 01202 01203 // This bit could be all there is of a 1 pixel wide region 01204 pMaskInfo->Length = 1; 01205 01206 // we are no longer looking for the start of the region 01207 LookingForStart = FALSE; 01208 } 01209 } 01210 else 01211 { 01212 // We are looking for the end of the region 01213 if (ThisBit!=0) 01214 { 01215 // we have reached the end of the region 01216 return; 01217 } 01218 else 01219 { 01220 // we are still in the region, so count the pixel 01221 pMaskInfo->Length++; 01222 } 01223 } 01224 01225 // Move the mask bit along to the next pixel 01226 Mask = Mask>>1; 01227 01228 // if we have exhasuted this byte, go on to the next one and reset the mask 01229 if (Mask==0) 01230 { 01231 Mask = 0x80; 01232 pByte++; 01233 } 01234 } 01235 01236 // if we have found part of a region at the end of the scan line, return it 01237 if (pMaskInfo->Length>0) 01238 return; 01239 01240 // Start the next scan line from the beginning 01241 XStartPos = 0; 01242 Mask = 0x80; 01243 } 01244 } 01245 01246