// $Id: maskedrr.cpp 1288 2006-06-09 13:16:24Z phil $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // The Masked Render region /* */ #include "camtypes.h" #include "maskedrr.h" //#include "doccolor.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "nodebmp.h" //#include "view.h" - in camtypes.h [AUTOMATICALLY REMOVED] // An implement to match the Declare in the .h file. CC_IMPLEMENT_DYNAMIC(MaskedRenderRegion, GRenderBitmap) // This will get Camelot to display the filename and linenumber of any memory allocations // that are not released at program exit #define new CAM_DEBUG_NEW // This table holds the number of bits set for each of the byte values 0 to 255. This table is // used to help speed up the counting of the number of set pixels in the mask INT32 MaskedRenderRegion::BitCountTable[256] = { 0, /* 0x0 */ 1, /* 0x1 */ 1, /* 0x2 */ 2, /* 0x3 */ 1, /* 0x4 */ 2, /* 0x5 */ 2, /* 0x6 */ 3, /* 0x7 */ 1, /* 0x8 */ 2, /* 0x9 */ 2, /* 0xA */ 3, /* 0xB */ 2, /* 0xC */ 3, /* 0xD */ 3, /* 0xE */ 4, /* 0xF */ 1, /* 0x10 */ 2, /* 0x11 */ 2, /* 0x12 */ 3, /* 0x13 */ 2, /* 0x14 */ 3, /* 0x15 */ 3, /* 0x16 */ 4, /* 0x17 */ 2, /* 0x18 */ 3, /* 0x19 */ 3, /* 0x1A */ 4, /* 0x1B */ 3, /* 0x1C */ 4, /* 0x1D */ 4, /* 0x1E */ 5, /* 0x1F */ 1, /* 0x20 */ 2, /* 0x21 */ 2, /* 0x22 */ 3, /* 0x23 */ 2, /* 0x24 */ 3, /* 0x25 */ 3, /* 0x26 */ 4, /* 0x27 */ 2, /* 0x28 */ 3, /* 0x29 */ 3, /* 0x2A */ 4, /* 0x2B */ 3, /* 0x2C */ 4, /* 0x2D */ 4, /* 0x2E */ 5, /* 0x2F */ 2, /* 0x30 */ 3, /* 0x31 */ 3, /* 0x32 */ 4, /* 0x33 */ 3, /* 0x34 */ 4, /* 0x35 */ 4, /* 0x36 */ 5, /* 0x37 */ 3, /* 0x38 */ 4, /* 0x39 */ 4, /* 0x3A */ 5, /* 0x3B */ 4, /* 0x3C */ 5, /* 0x3D */ 5, /* 0x3E */ 6, /* 0x3F */ 1, /* 0x40 */ 2, /* 0x41 */ 2, /* 0x42 */ 3, /* 0x43 */ 2, /* 0x44 */ 3, /* 0x45 */ 3, /* 0x46 */ 4, /* 0x47 */ 2, /* 0x48 */ 3, /* 0x49 */ 3, /* 0x4A */ 4, /* 0x4B */ 3, /* 0x4C */ 4, /* 0x4D */ 4, /* 0x4E */ 5, /* 0x4F */ 2, /* 0x50 */ 3, /* 0x51 */ 3, /* 0x52 */ 4, /* 0x53 */ 3, /* 0x54 */ 4, /* 0x55 */ 4, /* 0x56 */ 5, /* 0x57 */ 3, /* 0x58 */ 4, /* 0x59 */ 4, /* 0x5A */ 5, /* 0x5B */ 4, /* 0x5C */ 5, /* 0x5D */ 5, /* 0x5E */ 6, /* 0x5F */ 2, /* 0x60 */ 3, /* 0x61 */ 3, /* 0x62 */ 4, /* 0x63 */ 3, /* 0x64 */ 4, /* 0x65 */ 4, /* 0x66 */ 5, /* 0x67 */ 3, /* 0x68 */ 4, /* 0x69 */ 4, /* 0x6A */ 5, /* 0x6B */ 4, /* 0x6C */ 5, /* 0x6D */ 5, /* 0x6E */ 6, /* 0x6F */ 3, /* 0x70 */ 4, /* 0x71 */ 4, /* 0x72 */ 5, /* 0x73 */ 4, /* 0x74 */ 5, /* 0x75 */ 5, /* 0x76 */ 6, /* 0x77 */ 4, /* 0x78 */ 5, /* 0x79 */ 5, /* 0x7A */ 6, /* 0x7B */ 5, /* 0x7C */ 6, /* 0x7D */ 6, /* 0x7E */ 7, /* 0x7F */ 1, /* 0x80 */ 2, /* 0x81 */ 2, /* 0x82 */ 3, /* 0x83 */ 2, /* 0x84 */ 3, /* 0x85 */ 3, /* 0x86 */ 4, /* 0x87 */ 2, /* 0x88 */ 3, /* 0x89 */ 3, /* 0x8A */ 4, /* 0x8B */ 3, /* 0x8C */ 4, /* 0x8D */ 4, /* 0x8E */ 5, /* 0x8F */ 2, /* 0x90 */ 3, /* 0x91 */ 3, /* 0x92 */ 4, /* 0x93 */ 3, /* 0x94 */ 4, /* 0x95 */ 4, /* 0x96 */ 5, /* 0x97 */ 3, /* 0x98 */ 4, /* 0x99 */ 4, /* 0x9A */ 5, /* 0x9B */ 4, /* 0x9C */ 5, /* 0x9D */ 5, /* 0x9E */ 6, /* 0x9F */ 2, /* 0xA0 */ 3, /* 0xA1 */ 3, /* 0xA2 */ 4, /* 0xA3 */ 3, /* 0xA4 */ 4, /* 0xA5 */ 4, /* 0xA6 */ 5, /* 0xA7 */ 3, /* 0xA8 */ 4, /* 0xA9 */ 4, /* 0xAA */ 5, /* 0xAB */ 4, /* 0xAC */ 5, /* 0xAD */ 5, /* 0xAE */ 6, /* 0xAF */ 3, /* 0xB0 */ 4, /* 0xB1 */ 4, /* 0xB2 */ 5, /* 0xB3 */ 4, /* 0xB4 */ 5, /* 0xB5 */ 5, /* 0xB6 */ 6, /* 0xB7 */ 4, /* 0xB8 */ 5, /* 0xB9 */ 5, /* 0xBA */ 6, /* 0xBB */ 5, /* 0xBC */ 6, /* 0xBD */ 6, /* 0xBE */ 7, /* 0xBF */ 2, /* 0xC0 */ 3, /* 0xC1 */ 3, /* 0xC2 */ 4, /* 0xC3 */ 3, /* 0xC4 */ 4, /* 0xC5 */ 4, /* 0xC6 */ 5, /* 0xC7 */ 3, /* 0xC8 */ 4, /* 0xC9 */ 4, /* 0xCA */ 5, /* 0xCB */ 4, /* 0xCC */ 5, /* 0xCD */ 5, /* 0xCE */ 6, /* 0xCF */ 3, /* 0xD0 */ 4, /* 0xD1 */ 4, /* 0xD2 */ 5, /* 0xD3 */ 4, /* 0xD4 */ 5, /* 0xD5 */ 5, /* 0xD6 */ 6, /* 0xD7 */ 4, /* 0xD8 */ 5, /* 0xD9 */ 5, /* 0xDA */ 6, /* 0xDB */ 5, /* 0xDC */ 6, /* 0xDD */ 6, /* 0xDE */ 7, /* 0xDF */ 3, /* 0xE0 */ 4, /* 0xE1 */ 4, /* 0xE2 */ 5, /* 0xE3 */ 4, /* 0xE4 */ 5, /* 0xE5 */ 5, /* 0xE6 */ 6, /* 0xE7 */ 4, /* 0xE8 */ 5, /* 0xE9 */ 5, /* 0xEA */ 6, /* 0xEB */ 5, /* 0xEC */ 6, /* 0xED */ 6, /* 0xEE */ 7, /* 0xEF */ 4, /* 0xF0 */ 5, /* 0xF1 */ 5, /* 0xF2 */ 6, /* 0xF3 */ 5, /* 0xF4 */ 6, /* 0xF5 */ 6, /* 0xF6 */ 7, /* 0xF7 */ 5, /* 0xF8 */ 6, /* 0xF9 */ 6, /* 0xFA */ 7, /* 0xFB */ 6, /* 0xFC */ 7, /* 0xFD */ 7, /* 0xFE */ 8 /* 0xFF */ }; /******************************************************************************************** > MaskedRenderRegion::MaskedRenderRegion( DocRect ClipRegion, Matrix ConvertMatrix, FIXED16 ViewScale, UINT32 Depth, double dpi) Author: Rik_Heywood (Xara Group Ltd) Created: 11/4/95 Inputs: ClipRect - the Clipping rectangle ConvertMatrix - the Matrix to render through ViewScale - The Scale Factor dpi - Dots per inch Purpose: Constructor. Sends everything on to the base class. INT32 dpi changed to FIXED16 dpi (12/12/95) to improve the range of values allowed at the < 1000dpi settings that we will be using. ********************************************************************************************/ MaskedRenderRegion::MaskedRenderRegion( DocRect ClipRegion, Matrix ConvertMatrix, FIXED16 ViewScale, double dpi) : GRenderBitmap(ClipRegion, ConvertMatrix, ViewScale, 1, dpi) { // Some attrs we use. NULL by default pFillAttr = NULL; pStrokeAttr = NULL; Black = DocColour(0,0,0); White = DocColour(255,255,255); } /******************************************************************************************** > MaskedRenderRegion::~MaskedRenderRegion() Author: Rik_Heywood (Xara Group Ltd) Created: 11/4/95 Purpose: Default destructor ********************************************************************************************/ MaskedRenderRegion::~MaskedRenderRegion() { // Kill the fill attr if (pFillAttr!=NULL) { delete pFillAttr; pFillAttr = NULL; } // kill the stroke attr if (pStrokeAttr!=NULL) { delete pStrokeAttr; pStrokeAttr = NULL; } } /******************************************************************************************** > BOOL MaskedRenderRegion::StartRender() Author: Rik_Heywood (Xara Group Ltd) Created: 20/4/95 Returns: TRUE if it worked, FALSE if it failed Purpose: Starts the render region up. This version just calls the base class and allocates a couple of attributes used during the rendering. ********************************************************************************************/ BOOL MaskedRenderRegion::StartRender() { // Call the base class if (!GRenderBitmap::StartRender()) return FALSE; // If we got a bitmap, then clear it if (pBits!=NULL && pBitmapInfo!=NULL) { // Find out how many bytes there are to look at INT32 TotalBytes = pBitmapInfo->bmiHeader.biSizeImage; // clear it all out - a Set pixels is transparent, an Unset pixel is not memset(pBits, 0xFF, TotalBytes); } // Do our own thing - We need some attrs if (pFillAttr==NULL) pFillAttr = new FlatTranspFillAttribute(0); if (pStrokeAttr==NULL) pStrokeAttr = new StrokeTranspAttribute(0); // See if we got the ram we wanted if ((pFillAttr==NULL) || (pStrokeAttr==NULL)) return FALSE; // if we get here, everything has worked return TRUE; } /******************************************************************************************** > void MaskedRenderRegion::SetHostCaps(RenderCaps* pCaps) Author: Rik_Heywood (Xara Group Ltd) Created: 24/4/95 Inputs: pCaps - pointer to the render caps for the host render region Purpose: Tells the mask region what attributes are considered complex. ********************************************************************************************/ void MaskedRenderRegion::SetHostCaps(RRCaps* pCaps) { // Make a copy of the host regions caps HostCaps = *pCaps; } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawPathToOutputDevice(Path* pPath) Author: Rik_Heywood (Xara Group Ltd) Created: 24/4/95 Inputs: pPath - The path that needs rendering Purpose: Renders the path into the mask. It makes sure that all the attributes are set up correctly first though ********************************************************************************************/ void MaskedRenderRegion::DrawPathToOutputDevice(Path* pPath, PathShape) { // Save the context SaveContext(); BOOL RenderFill = FALSE; // Get the current fill attr FillGeometryAttribute* pFillAttr = (FillGeometryAttribute*) CurrentAttrs[ATTR_FILLGEOMETRY].pAttr; if (pFillAttr->GetBitmap() != NULL && pFillAttr->GetBitmap()->GetBPP() <= 8) { INT32 TranspIndex; // If it's a masked bitmap fill, then we'll need to actually render it // (but we'll force all the non-masked pixels to be rendered black) if (pFillAttr->GetBitmap()->GetTransparencyIndex(&TranspIndex)) RenderFill = TRUE; } if (RenderFill) { BOOL OldVMState = RenderFlags.VeryMono; RenderFlags.VeryMono = TRUE; // Forces non-masked pixels to be plotted black // Draw the path, with the bitmap fill GRenderBitmap::DrawPathToOutputDevice(pPath); RenderFlags.VeryMono = OldVMState; } else { // Does this shape make use of complex things if (TestForComplexShape(&HostCaps)) SetNextShapeColour(Black); else SetNextShapeColour(White); // Draw the path GRenderBitmap::DrawPathToOutputDevice(pPath); } // restore the context RestoreContext(); } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawRect(DocRect* pRectToRender) Author: Rik_Heywood (Xara Group Ltd) Created: 6/4/95 Inputs: pRectToRender - The Rectangle that we need to render Purpose: This function will examine the attributes etc to see if this represents a simple or compex shape. It will set up the attributes according to the result of this and then call the base class version of the function. ********************************************************************************************/ void MaskedRenderRegion::DrawRect(DocRect* pRectToRender) { // Save the context SaveContext(); // Does this shape make use of complex things if (TestForComplexShape(&HostCaps)) SetNextShapeColour(Black); else SetNextShapeColour(White); // Draw the path GRenderBitmap::DrawRect(pRectToRender); // restore the context RestoreContext(); } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawLine(const DocCoord &StartPoint, const DocCoord &EndPoint) Author: Rik_Heywood (Xara Group Ltd) Created: 6/4/95 Inputs: StartPoint, EndPoint - the coords to draw a line between Purpose: This function will examine the attributes etc to see if this represents a simple or compex shape. It will set up the attributes according to the result of this and then call the base class version of the function. ********************************************************************************************/ void MaskedRenderRegion::DrawLine(const DocCoord &StartPoint, const DocCoord &EndPoint) { // Save the context SaveContext(); // Does this shape make use of complex things if (TestForComplexShape(&HostCaps)) SetNextShapeColour(Black); else SetNextShapeColour(White); // Draw the path GRenderBitmap::DrawLine(StartPoint, EndPoint); // restore the context RestoreContext(); } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawPixel(const DocCoord &Point) Author: Rik_Heywood (Xara Group Ltd) Created: 6/4/95 Inputs: Point - the coord to draw the pixel in Purpose: This function will examine the attributes etc to see if this represents a simple or compex shape. It will set up the attributes according to the result of this and then call the base class version of the function. ********************************************************************************************/ void MaskedRenderRegion::DrawPixel(const DocCoord &Point) { // Save the context SaveContext(); // Does this shape make use of complex things if (TestForComplexShape(&HostCaps)) SetNextShapeColour(Black); else SetNextShapeColour(White); // Draw the path GRenderBitmap::DrawPixel(Point); // restore the context RestoreContext(); } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawBitmap(const DocCoord &Point, KernelBitmap* pBitmap) Author: Rik_Heywood (Xara Group Ltd) Created: 6/4/95 Inputs: Point - The position to draw the bitmap at pBitmap - the bitmap that needs drawing Purpose: This function will examine the attributes etc to see if this represents a simple or compex shape. It will set up the attributes according to the result of this and then call the base class version of the function. ********************************************************************************************/ void MaskedRenderRegion::DrawBitmap(const DocCoord &Point, KernelBitmap* pBitmap) { // Save the context SaveContext(); // Does this shape make use of complex things if (TestForComplexShape(&HostCaps)) SetNextShapeColour(Black); else SetNextShapeColour(White); // Draw the path GRenderBitmap::DrawBitmap(Point, pBitmap); // restore the context RestoreContext(); } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawBitmap(const DocCoord &Point, UINT32 BitmapID, UINT32 ToolID) Author: Rik_Heywood (Xara Group Ltd) Created: 6/4/95 Inputs: Point - the position to draw the bitmap at BitmapID - The ID of the bitmap to render ToolID - the ID of the tool that the bitmap belongs to Purpose: This function will examine the attributes etc to see if this represents a simple or compex shape. It will set up the attributes according to the result of this and then call the base class version of the function. ********************************************************************************************/ void MaskedRenderRegion::DrawBitmap(const DocCoord &Point, UINT32 BitmapID, UINT32 ToolID) { // Save the context SaveContext(); // Does this shape make use of complex things if (TestForComplexShape(&HostCaps)) SetNextShapeColour(Black); else SetNextShapeColour(White); // Draw the path GRenderBitmap::DrawBitmap(Point, BitmapID, ToolID); // restore the context RestoreContext(); } BOOL MaskedRenderRegion::DrawTransformedBitmap(NodeBitmap *pNodeBitmap) { // Save the context SaveContext(); // Work out if we can do this bitmap directly BOOL CanDoBitmap = FALSE; // Does this shape make use of complex things if (!(TestForComplexShape(&HostCaps) || pNodeBitmap->NeedsTransparency())) { // See what kind of bitmaps this render region can do if (HostCaps.ArbitraryBitmaps) { // We can do anything... CanDoBitmap = TRUE; } else { if (HostCaps.SimpleBitmaps) { // Check that the bitmap area is rectangular, and is perpendicular to // the x and y axes. if (pNodeBitmap->HasSimpleOrientation(this)) { // Yes - simple scaling - the render region can do this. CanDoBitmap = TRUE; } } } } // Here we set up reasonable attributes - we want to fill the bitmap // path but not stroke it. NB. This is very important - do not remove // otherwise the mask will be wrong! DocColour colorBlack( COLOUR_BLACK ); SetFillColour( colorBlack ); DocColour colorNone( COLOUR_NONE ); SetLineColour( colorNone ); if (CanDoBitmap) { SetNextShapeColour(White); // Draw the path (that represents the bitmap object) GRenderBitmap::DrawPathToOutputDevice(&pNodeBitmap->InkPath); } else { if (pNodeBitmap->NeedsTransparency()) { // It's a masked bitmap, so we'll need to actually render the non-masked // pixels as black BOOL OldVMState = RenderFlags.VeryMono; RenderFlags.VeryMono = TRUE; // Forces non-masked pixels to be plotted black // Call base class to plot the bitmap RenderRegion::DrawTransformedBitmap(pNodeBitmap); RenderFlags.VeryMono = OldVMState; } else { SetNextShapeColour(Black); // Draw the path (that represents the bitmap object) GRenderBitmap::DrawPathToOutputDevice(&pNodeBitmap->InkPath); } } // restore the context RestoreContext(); return TRUE; } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawDragRect(DocRect *RectToRender) Author: Rik_Heywood (Xara Group Ltd) Created: 6/4/95 Inputs: RectToRender - The Rectangle Purpose: None - Does nothing ********************************************************************************************/ void MaskedRenderRegion::DrawDragRect(DocRect *RectToRender) { } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawBlob(DocCoord p, BlobType type) Author: Rik_Heywood (Xara Group Ltd) Created: 6/4/95 Inputs: p - A coord type - The type of blob Purpose: None - Does nothing ********************************************************************************************/ void MaskedRenderRegion::DrawBlob(DocCoord p, BlobType type) { } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawCross(const DocCoord &Point, const UINT32 Size) Author: Rik_Heywood (Xara Group Ltd) Created: 6/4/95 Inputs: Point - a Coord Size - the size of the cross Purpose: None - Does nothing ********************************************************************************************/ void MaskedRenderRegion::DrawCross(const DocCoord &Point, const UINT32 Size) { } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawBitmapBlob(const DocCoord &Point, KernelBitmap* BlobShape) Author: Rik_Heywood (Xara Group Ltd) Created: 6/4/95 Inputs: Point - A Coord BlobShape - the bitmap to use Purpose: None - Does nothing ********************************************************************************************/ void MaskedRenderRegion::DrawBitmapBlob(const DocCoord &Point, KernelBitmap* BlobShape) { } /******************************************************************************************** > virtual void MaskedRenderRegion::DrawBitmapBlob(const DocCoord &Point, UINT32 BitmapID, UINT32 ToolID) Author: Rik_Heywood (Xara Group Ltd) Created: 6/4/95 Inputs: Point - A coord BitmapID - the ID of a bitmap ToolID - the Id of the tool the bitmap resource is in Purpose: None - Does nothing ********************************************************************************************/ void MaskedRenderRegion::DrawBitmapBlob(const DocCoord &Point, ResourceID resID ) { } /******************************************************************************************** > void MaskedRenderRegion::SetNextShapeColour(DocColour& RequiredCol) Author: Rik_Heywood (Xara Group Ltd) Created: 20/4/95 Inputs: RequiredCol - The colour to replace fill and stroke colours with Purpose: Sets all the attributes up so that we can render into our mask. It will boil everything down to a flat fill and stroke ready to be rendered into the mask. The colour passed in will probably be Black or White, but I left it open in case I thought of some other use for this. ********************************************************************************************/ void MaskedRenderRegion::SetNextShapeColour(DocColour& RequiredCol) { // Find out about the fill attr ColourFillAttribute* pColFillAttr = (ColourFillAttribute*) CurrentAttrs[ATTR_FILLGEOMETRY].pAttr; if ((pColFillAttr!=NULL) && (pColFillAttr->IS_KIND_OF(GradFillAttribute))) { // This is a grad fill, so just set the colour as required SetFillColour(RequiredCol); } else { // Is there a fill colour of any kind DocColour MyFillColour = RR_FILLCOLOUR(); // See if it is 'no colour' if (!MyFillColour.IsTransparent()) { // Nope, its a real colour alright, so we had better set the fill colour SetFillColour(RequiredCol); } } // Find out about the line colour DocColour MyStrokeColour = RR_STROKECOLOUR(); // See if it is 'no colour' if (!MyStrokeColour.IsTransparent()) { // Nope, its a real colour alright, so we had better set the fill colour SetLineColour(RequiredCol); } // Set Fill transp to none if (pFillAttr!=NULL) RenderRegion::SetTranspFillGeometry(pFillAttr, FALSE); // Set the stroke transp to none if (pStrokeAttr!=NULL) RenderRegion::SetLineTransp(pStrokeAttr, FALSE); } /******************************************************************************************** > BOOL MaskedRenderRegion::SpreadMask() Author: Rik_Heywood (Xara Group Ltd) Created: 15/5/95 Returns: TRUE if the mask was spread, FALSE if there was no mask in the first place Purpose: Spreads the mask out by a pixel. This allows us to make the area that is blitted slightly bigger to cover up any differences between the device resolution and the bitmap resolution. This function will grow the mask above, below, to the left and right by a single pixel. If this is not enough, call this function more than once. ********************************************************************************************/ BOOL MaskedRenderRegion::SpreadMask() { // If there is a bitmap if (pBits!=NULL && pBitmapInfo!=NULL) { // Get the scan line size in bytes INT32 ScanLineByteSize = (pBitmapInfo->bmiHeader.biWidth+7)/8; // Round it up to the nearest word boundary. Note, this is still a count of bytes INT32 ScanLineWordSize = ((ScanLineByteSize+3)/4)*4; // Start looping through all the scan lines in the mask, // going from top to bottom, moving set pixels up LPBYTE CurrentByte = NULL; LPBYTE ByteAbove = NULL; INT32 i; for (i=1; ibmiHeader.biHeight; i++) { // point CurrentByte at the start of the next scan line CurrentByte = pBits + (i*ScanLineWordSize); ByteAbove = pBits + ((i-1)*ScanLineWordSize); // Go along the scan line BOOL SetHighBit = FALSE; for (INT32 j=0; j>1); } // Or this byte with the one in the scan line above BYTE Result = BYTE(~(*ByteAbove)) | Current; *ByteAbove = BYTE(~Result); // Move to the next byte CurrentByte++; ByteAbove++; } } // Start looping through all the scan lines in the mask, // going from bottom to top, moving set pixels down CurrentByte = NULL; LPBYTE ByteBelow = NULL; for (i=pBitmapInfo->bmiHeader.biHeight-2; i>=0; i--) { // point CurrentByte at the start of the next scan line CurrentByte = pBits + (i*ScanLineWordSize) + ScanLineByteSize; ByteBelow = pBits + ((i+1)*ScanLineWordSize) + ScanLineByteSize; // Go along the scan line BOOL SetLowBit = FALSE; for (INT32 j=ScanLineByteSize-1; j>=0; j--) { // Try and set the leading pixel on the current byte BYTE Mask = 0x80; BYTE Current = BYTE(~(*CurrentByte)); // loop though the mask BOOL Found = FALSE; while (Mask!=0) { // See if we have found the least sig. pixel yet if ((Mask & Current) != 0) { Found = TRUE; break; } // Move the mask along a bit Mask = Mask >> 1; } // Set the low bit if needed if (SetLowBit) { Current = Current | 0x01; SetLowBit = FALSE; } // If we found a bit in this byte, set the bit next to the most sig bit if (Found) { if (Mask==0x80) SetLowBit = TRUE; else Current = Current | (Mask<<1); } // Or this byte with the one in the scan line below BYTE Result = BYTE(~(*ByteBelow)) | Current; *ByteBelow = BYTE(~Result); // Move to the next byte CurrentByte--; ByteBelow--; } } } return TRUE; } /******************************************************************************************** > INT32 MaskedRenderRegion::FindCoverage(BOOL AnyCoverageReturns100 = FALSE) Author: Rik_Heywood (Xara Group Ltd) Created: 21/4/95 Inputs: AnyConverageReturns100 - In most (if not all) calls to this function, the caller is only interested in whether coverage is equal to zero or not (i.e. "Do I have to bother rendering anything?"). If you set this flag to TRUE, this function will return 100% immediately if it finds a single pixel set in the mask, or 0% only if there are no pixels set in the mask. This is thus a much faster test of "do we need to render" because it usually doesn't have to scan far before it finds a pixel to plot. (Added by Jason, 1/7/96) Returns: 0 - 100. This represents the percentage of the masked bitmap that has pixels set in it. A value of 0 means that there are no pixels set in the mask. You can take this value to mean 'do not bother trying to display the bitmap cos none of it is visible'. A value of 100 means that every pixel in the mask is set so no clever masked plotting of the bitmap is required. (or, if the AnyConverageReturns100 flag was set, a value of 100 just means that there was at least one pixel requiring plotting) Purpose: Finds out how much of the mask has been set. ********************************************************************************************/ INT32 MaskedRenderRegion::FindCoverage(BOOL AnyCoverageReturns100) { INT32 TotalPixels = 0; INT32 TotalClearPixels = 0; if (pBits!=NULL && pBitmapInfo!=NULL) { // Get the scan line size in bytes const INT32 ScanLineByteSize = (pBitmapInfo->bmiHeader.biWidth+7)/8; // Round it up to the nearest word boundary. Note, this is still a count of bytes const INT32 ScanLineWordSize = ((ScanLineByteSize+3)/4)*4; // Work out how many padding pixels (bits) are on the end of the scanline const INT32 EndPixels = 8- ((ScanLineByteSize*8) - pBitmapInfo->bmiHeader.biWidth); // The last byte of each scanline may not use all its pixels, so we build a mask, // which is used to discount padding pixels from consideration BYTE Mask = 0x0; { BYTE Bit = 0x80; for (INT32 i=0; i>i; } // Start looping through all the scan lines in the mask LPBYTE CurrentByte = NULL; for (INT32 i=0; ibmiHeader.biHeight; i++) { // point CurrentByte at the start of the next scan line CurrentByte = pBits + (i*ScanLineWordSize); // Count this scan line of pixels TotalPixels += pBitmapInfo->bmiHeader.biWidth; // Go along the scan line, counting pixels for (INT32 j=0; j=100) Result = 99; // Tell them what percentage of pixels were set TRACEUSER( "Rik", _T("Coverage = %ld\n"), Result); return Result; } /******************************************************************************************** > INT32 MaskedRenderRegion::FindMaskDpi() Author: Rik_Heywood (Xara Group Ltd) Created: 30/4/95 Returns: The Dpi of the mask in this region Purpose: This function is used to find out the DPI that the region was created at. This is important as the device it is displaying to may have a different dpi and the difference has to be compensated for. Returns a INT32 form of the dpi As most printing and masking related items only require non-fractional dpis then this should not be a problem. So return a rounded up form of the stored double form. ********************************************************************************************/ INT32 MaskedRenderRegion::FindMaskDpi() { // tell them about the dpi // Need to return a rounded form of the stored double dpi return (INT32)(PixelsPerInch + 0.5); } /******************************************************************************************** > double MaskedRenderRegion::FindMaskDpi() Author: Neville_Humphrys (Xara Group Ltd) Created: 12/12/95 Returns: The Dpi of the mask in this region Purpose: This function is used to find out the DPI that the region was created at. This is important as the device it is displaying to may have a different dpi and the difference has to be compensated for. Returns the new double form of the dpi ********************************************************************************************/ //double MaskedRenderRegion::FindMaskDpi() //{ // tell them about the dpi // return PixelsPerInch; //} /******************************************************************************************** > void MaskedRenderRegion::GetFirstMaskRegion(MaskRegion* pMaskInfo) Author: Rik_Heywood (Xara Group Ltd) Created: 21/4/95 Outputs: pMaskInfo - holds info about the first region as output Purpose: This function finds the first scan line section in the mask that indicates pixels need to be set. When it finds the next section it fills in the info about it in pMaskInfo and returns. If there are no regions to be found in the mask then the Length member of pMaskInfo will be set to zero. This is your clue that there are no scan line sections to process. SeeAlso: MaskedRenderRegion::GetNextMaskRegion; struct MaskRegion ********************************************************************************************/ void MaskedRenderRegion::GetFirstMaskRegion(MaskRegion* pMaskInfo) { // Set up the starting conditions pMaskInfo->x = 0; pMaskInfo->y = 0; pMaskInfo->Length = 0; // start looking for a bit we have to blit ScanMaskFrom(pMaskInfo); } /******************************************************************************************** > void MaskedRenderRegion::GetNextMaskRegion(MaskRegion* pMaskInfo) Author: Rik_Heywood (Xara Group Ltd) Created: 21/4/95 Inputs: pMaskInfo - Holds info about the last region that was found Outputs: pMaskInfo - but holds info about the next region as output Purpose: This function finds the next scan line section in the mask that indicates pixels need to be set. It uses the info in the pMaskInfo param to work out where to start looking from. When it finds the next section, which could be on the same scan line as the present one, it fills in the info about it in pMaskInfo and returns. If there are no more regions to be found in the mask then the Length member of pMaskInfo will be set to zero. This is your clue that there are no more scan line sections to process. SeeAlso: MaskedRenderRegion::GetFirstMaskRegion; struct MaskRegion ********************************************************************************************/ void MaskedRenderRegion::GetNextMaskRegion(MaskRegion* pMaskInfo) { // Find the end of the last scan section // Move to the end of the last region pMaskInfo->x += pMaskInfo->Length; // are we at the end of the scan line if (pMaskInfo->x >= pBitmapInfo->bmiHeader.biWidth) { pMaskInfo->x = 0; pMaskInfo->y++; } // Reset the length to zero pMaskInfo->Length = 0; // start looking for a bit we have to blit ScanMaskFrom(pMaskInfo); } /******************************************************************************************** > void MaskedRenderRegion::ScanMaskFrom(MaskRegion* pMaskInfo) Author: Rik_Heywood (Xara Group Ltd) Created: 23/4/95 Inputs: pMaskInfo - Holds the position to start looking from Outputs: pMaskInfo - Hold info about the next scan section to look at Purpose: Searchs the mask for a section that means we will have to blit something. The starting position of the section and the length of the section are put into pMaskInfo and returned. pMaskInfo->Length will be set to zero if there are no more sections in the mask. ********************************************************************************************/ void MaskedRenderRegion::ScanMaskFrom(MaskRegion* pMaskInfo) { // Assume we will find no more scan sections pMaskInfo->Length = 0; // get a mask to look along the bits in the mask INT32 Mask = 0x80; INT32 XStartPos = pMaskInfo->x; INT32 YStartPos = pMaskInfo->y; // Set the mask up correctly, as the X starting pos may not be at the start of a byte if (XStartPos!=0) { // Go through the byte, setting the bits back to 1 as needed INT32 PixelNum = (XStartPos/8) * 8; while (PixelNum < XStartPos) { // Shift the bit along Mask = Mask>>1; // Count the pixel PixelNum++; } } // Find out how many bytes in a scan line INT32 ScanLineSize = (pBitmapInfo->bmiHeader.biWidth+7)/8; ScanLineSize = (ScanLineSize+3)&~3; // We start out looking for the start of a region BOOL LookingForStart = TRUE; // a pointer to the byte we are dealing with LPBYTE pByte = NULL; // try and find the start of the first region for (INT32 j=YStartPos; jbmiHeader.biHeight; j++) { // Get the byte we are interested in pByte = pBits + (j*ScanLineSize) + (XStartPos/8); // start going accross the scan line for (INT32 i=XStartPos; ibmiHeader.biWidth; i++) { // Find out what this bit is (1 or 0) INT32 ThisBit = (*pByte) & Mask; // what are we looking for - the start or the end of a region. if (LookingForStart) { if (ThisBit == 0) { // Set the start position in the mask region pMaskInfo->x = i; pMaskInfo->y = j; // This bit could be all there is of a 1 pixel wide region pMaskInfo->Length = 1; // we are no longer looking for the start of the region LookingForStart = FALSE; } } else { // We are looking for the end of the region if (ThisBit!=0) { // we have reached the end of the region return; } else { // we are still in the region, so count the pixel pMaskInfo->Length++; } } // Move the mask bit along to the next pixel Mask = Mask>>1; // if we have exhasuted this byte, go on to the next one and reset the mask if (Mask==0) { Mask = 0x80; pByte++; } } // if we have found part of a region at the end of the scan line, return it if (pMaskInfo->Length>0) return; // Start the next scan line from the beginning XStartPos = 0; Mask = 0x80; } }