// $Id: cmxicmds.cpp 1282 2006-06-09 09:46:49Z alex $ /* @@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============================ */ // handles CMX commands #include "camtypes.h" //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "riffform.h" #include "progress.h" #include "nodepath.h" #include "nodebmp.h" #include "nodershp.h" #include "cmxifltr.h" #include "cmxistut.h" #include "cmxidata.h" #include "cmxibits.h" #include "cmxibitm.h" //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "riffform.h" #include "progress.h" #include "nodepath.h" //#include "nev.h" #include "nodetxts.h" #include "unicdman.h" #include "nodetxtl.h" /******************************************************************************************** > BOOL CMXImportFilter::Stage4_ConvertPage(void) Author: Ben_Summers (Xara Group Ltd) Created: 07/08/96 Inputs: None Returns: error flag Purpose: Goes through the page processing the commands. ********************************************************************************************/ BOOL CMXImportFilter::Stage4_ConvertPage(void) { TRACEUSER( "Ben", _T("Stage4_ConvertPage\n")); // plan here -- read the index entries to find the start of the page, // wander over to the right position in the file and start processing // we simply loop around calling the process command function, and // sorting out the progress thingy. Admittedly, this does mean that // during the loading of the description sections you'll just get a // zero progress count. Oh well, c'est la vie. // find the page index, and grab the first page in it if(Data->MasterIndexEntries[cmxMASTERIN_PAGE] == 0) CMXFORMATERROR(FALSE) TRACEUSER( "Ben", _T("index page at %d?\n"), Data->MasterIndexEntries[cmxMASTERIN_PAGE]); Seek(Data->MasterIndexEntries[cmxMASTERIN_PAGE]); RIFFck chdr; pFile->read(&chdr, sizeof(chdr)); if(chdr.ckID != cmxRIFFCI_PageIndex) CMXFORMATERROR(FALSE) // get the index header CI_READDATA(SimpleIndexHeader, ih) if(ih.RecordCount < 1) CMXFORMATERROR(FALSE) // get the first index entry CI_READDATA(PageIndexEntry, ie) TRACEUSER( "Ben", _T("Page is at %d\n"), ie.PageOffset); // seek to that position, and check the riff header Seek(ie.PageOffset); pFile->read(&chdr, sizeof(chdr)); if(chdr.ckID != cmxRIFFCI_Page) CMXFORMATERROR(FALSE) // didn't get one of those page things there. Oh dear... // set the end position of the page INT32 PageEndFileLoc = Tell() + chdr.ckSize; Data->InPage = TRUE; // progress system stuff INT32 wobble = 0; // run through the loop... what follows is a load of instructions TRACEUSER( "Ben", _T("processing commands:\n")); while(Data->InPage == TRUE) { // process a command if(!ProcessCommand(&wobble)) return FALSE; // error // check to see if we've over run the page... if(Tell() >= PageEndFileLoc) Data->InPage = FALSE; // progress system if(Data->CommandsInPage != -1) { wobble++; if(!Data->pProgress->Update(wobble)) { TRACEUSER( "claude", _T("User Escaped!\n")); Error::SetError(_R(IDN_CMXCANCELIMPORT)); //TRACEUSER( "claude", _T("after SetError()\n")); //InformError(_R(IDN_CMXCANCELIMPORT));//_R(IDN_USER_CANCELLED));//Error::GetErrorNumber()); TRACEUSER( "claude", _T("after InformError()\n")); return FALSE; // user pressed escape... abort abort! } } } TRACEUSER( "Ben", _T("finished processing commands\n")); TRACEUSER( "claude", _T("finished processing commands\n")); // that's it, chaps return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Stage5_ConvertPage(void) Author: Ben_Summers (Xara Group Ltd) Created: 08/08/96 Inputs: None Returns: error flag Purpose: process a CMX command -- mainly a dispatch function ********************************************************************************************/ #define PC_DISPATCH(instr) case cmxINSTR_##instr: \ TRACEUSER( "Ben", _T(" * " #instr "\n")); \ TRACEUSER( "Claude", _T(" * " #instr "\n")); \ if(!Process_##instr()) return FALSE; break; #define NEEDLAYER {if(Data->pCurrentLayer == NULL) {TRACEUSER( "Ben", _T("no layer\n")); \ CMXFORMATERROR(FALSE)}} BOOL CMXImportFilter::ProcessCommand(INT32 *ProgressThingy) { // get the current file position INT32 CommandEndFilePos = Tell(); // read the command header CI_READDATA(CommandHeader, ch) // if the command thing is negative, we may need to fudge it if we're going 16 bitness if(ch.Code < 0 && !Is32Bit) ch.Code = 0 - ch.Code; CommandEndFilePos += ch.Size; // get the file pos of the end of the instruction // dispatch it to the relevant function switch(ch.Code) { PC_DISPATCH(BeginPage) PC_DISPATCH(EndPage) PC_DISPATCH(BeginLayer) PC_DISPATCH(EndLayer) PC_DISPATCH(BeginGroup) PC_DISPATCH(EndGroup) PC_DISPATCH(EndSection) PC_DISPATCH(PolyCurve) PC_DISPATCH(Rectangle) // Graeme ( 1-2-00 ). PC_DISPATCH(AddGlobalTransform) PC_DISPATCH(SetGlobalTransform) PC_DISPATCH(RestoreLastGlobalTransform) PC_DISPATCH(DrawImage) PC_DISPATCH(AddClippingRegion) PC_DISPATCH(RemoveLastClippingRegion) PC_DISPATCH(ClearClipping) PC_DISPATCH(BeginTextStream) PC_DISPATCH(TextFrame) PC_DISPATCH(Characters) PC_DISPATCH(CharInfo) PC_DISPATCH(BeginParagraph) PC_DISPATCH(EndParagraph) PC_DISPATCH(EndTextStream) case cmxINSTR_JumpAbsolute: { CI_READDATA(JumpAbsolute, ja) TRACEUSER( "Ben", _T(" * JumpAbsolute to %d\n"), ja.Offset); TRACEUSER( "Claude", _T(" * JumpAbsolute to %d\n"), ja.Offset); // got a jump absolute thingy -- alter the next thing to skip over something // silly that Corel's lovely amazingly neat method of storing stuff in a // file has stuck in our way CommandEndFilePos = ja.Offset; // make us seek there later // JumpAbsolutes aren't counted as instructions, for some reason if(ProgressThingy != NULL) (*ProgressThingy)--; } break; default: // don't understand this command, don't need to do anything special here TRACEUSER( "Ben", _T(" * <>\n")); TRACEUSER( "Claude", _T(" * <>\n")); TRACEUSER( "Graeme", _T(" * <>\n")); break; } // finally, check that we're in the right position in the file for the next command if(Tell() != CommandEndFilePos) Seek(CommandEndFilePos); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_EndPage(void) Author: Ben_Summers (Xara Group Ltd) Created: 08/08/96 Inputs: None Returns: error flag Purpose: process a EndPage command ********************************************************************************************/ BOOL CMXImportFilter::Process_EndPage(void) { // stop it. Stop it now. I mean it, stop processing that page right now // or I set the killer carrot on you, and you wouldn't want that, would you? Data->InPage = FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_BeginPage(void) Author: Ben_Summers (Xara Group Ltd) Created: 08/08/96 Inputs: None Returns: error flag Purpose: process a BeginPage command ********************************************************************************************/ BOOL CMXImportFilter::Process_BeginPage(void) { // read the begin page structure from the file CI_READDATA(BeginPage, bp) // set progress system up (again) Data->CommandsInPage = bp.InstructionCount; if(Data->pProgress != NULL) { delete Data->pProgress; Data->pProgress = NULL; } Data->pProgress = new Progress(_R(IDT_CMX_IMPORTMSG), Data->CommandsInPage, FALSE); if(Data->pProgress == NULL) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_EndLayer(void) Author: Ben_Summers (Xara Group Ltd) Created: 09/08/96 Inputs: None Returns: error flag Purpose: process a EndLayer command ********************************************************************************************/ BOOL CMXImportFilter::Process_EndLayer(void) { if(Data->pCurrentLayer == NULL) // then we weren't doing a layer CMXFORMATERROR(FALSE) // mark as not doing a layer Data->pCurrentLayer = NULL; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_BeginLayer(void) Author: Ben_Summers (Xara Group Ltd) Created: 09/08/96 Inputs: None Returns: error flag Purpose: process a BeginLayer command ********************************************************************************************/ BOOL CMXImportFilter::Process_BeginLayer(void) { if(Data->pCurrentLayer != NULL) // already doing a layer CMXFORMATERROR(FALSE) // read the data from the file CI_READDATA(BeginLayer, bl) TRACEUSER( "Ben", _T(" layer name = %s\n"), (TCHAR *)(*bl.pLayerName)); // create a new layer object Data->pCurrentLayer = new CMXImportLayer; if(Data->pCurrentLayer == NULL) return FALSE; // add the layer to the list Data->Layers.AddTail(Data->pCurrentLayer); // set the name of the layer Data->pCurrentLayer->SetName(bl.pLayerName); // clear up delete bl.pLayerName; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_BeginGroup(void) Author: Ben_Summers (Xara Group Ltd) Created: 09/08/96 Inputs: None Returns: error flag Purpose: process a BeginGroup command ********************************************************************************************/ BOOL CMXImportFilter::Process_BeginGroup(void) { NEEDLAYER if(!Data->pCurrentLayer->StartGroup()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_EndGroup(void) Author: Ben_Summers (Xara Group Ltd) Created: 09/08/96 Inputs: None Returns: error flag Purpose: process a EndGroup command ********************************************************************************************/ BOOL CMXImportFilter::Process_EndGroup(void) { NEEDLAYER if(!Data->pCurrentLayer->EndGroup()) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_PolyCurve(void) Author: Ben_Summers (Xara Group Ltd) Created: 09/08/96 Inputs: None Returns: error flag Purpose: process a PolyCurve command ********************************************************************************************/ BOOL CMXImportFilter::Process_PolyCurve(void) { NEEDLAYER // read everything I need to know from the file CI_READDATA(PolyCurve, pc) // check to see if there's a container to think about // ONLY polycurves will have containers in a meaningful way -- other objects // needn't bother to check the flag if((pc.RenderAttributes.Mask & cmxRENDATTRMASK_CONTAIN) != 0) { if(!Process_PolyCurveContainer(pc)) return FALSE; } // process it... create a node path with the nice path we've just got NodePath *pPNode = new NodePath; if(pPNode == NULL || !pPNode->SetUpPath(pc.PointList->GetNumCoords() + 4)) return FALSE; if(!pPNode->InkPath.CloneFrom(*pc.PointList)) return FALSE; pPNode->InkPath.IsFilled = pc.PointList->IsFilled; pPNode->InkPath.IsStroked = pc.PointList->IsStroked; if(!pPNode->InkPath.EnsureValid()) return FALSE; Node *pNode = pPNode; // do all the necessary things on the path if(!TransformNode(pNode) || !SetAttributesForNode(pNode, &pc.RenderAttributes) || !ClipNode(&pNode) || !ApplyAttributesToNode(pNode)) return FALSE; // add the node Data->pCurrentLayer->AddNode(pNode); // clear up after ourselves delete pc.PointList; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_PolyCurveContainer(cmxiPolyCurve &pc) Author: Ben_Summers (Xara Group Ltd) Created: 26/08/96 Inputs: None Returns: error flag Purpose: does all the stuff ********************************************************************************************/ BOOL CMXImportFilter::Process_PolyCurveContainer(cmxiPolyCurve &pc) { // right then, we've got to process one of those there containers // we get a reference to a procedure of things inside a page // check the procedure reference if(pc.RenderAttributes.ContainerSpec.ContainerReference <= 0 || pc.RenderAttributes.ContainerSpec.ContainerReference > Data->NumProcedures) CMXFORMATERROR(FALSE) // see if we can get a position for it INT32 Position = Data->Procedures[pc.RenderAttributes.ContainerSpec.ContainerReference-1].Position; if(Position <= 0) CMXFORMATERROR(FALSE) // store the position of the file for later INT32 StartFilePos = Tell(); // jump to the position of the vector fill procedure Seek(Position); // and see if we can find a draw image command in there somewhere -- skip the header RIFFck hdr; pFile->read(&hdr, sizeof(hdr)); // I'm not going to check the type of this chunk as corel specify one type, and put // another in the file. Stupid documentionness BOOL EndProcLoc = Tell() + hdr.ckSize; // make a copy of the path of the polycurve, and set a new clipping region to it Path *pClipPath = new Path; if(pClipPath == NULL || !pClipPath->Initialise()) return FALSE; // no pathy thingy for us to use pClipPath->CloneFrom(*pc.PointList); CMXImportClipper *pClipper = new CMXImportClipper(pClipPath, TRUE); if(pClipper == NULL) return FALSE; Data->ClipperStack.Push(pClipper); // run through the commands processing them TRACEUSER( "Ben", _T("processing commands in container procedure:\n")); BOOL InProc = TRUE; Data->EndSectionFound = FALSE; while(InProc == TRUE) { // process a command if(!ProcessCommand()) return FALSE; // error if(Data->EndSectionFound == TRUE) InProc = FALSE; // check to see if we've over run the page... if(Tell() >= EndProcLoc) InProc = FALSE; } TRACEUSER( "Ben", _T("finished processing commands in procedure\n")); // go back to where we were in the file Seek(StartFilePos); // get rid of the clipping region delete Data->ClipperStack.Pop(); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_Rectangle ( void ) Author: Graeme_Sutherland (Xara Group Ltd) Created: 01/02/00 Inputs: - Returns: TRUE if success, FALSE otherwise. Purpose: Processes a rectangle command from within the CMX filter. ********************************************************************************************/ BOOL CMXImportFilter::Process_Rectangle ( void ) { NodeRegularShape *pRectangle = NULL; Matrix RectMatrix; DocCoord MajorAxis ( 0, 0 ); DocCoord MinorAxis ( 0, 0 ); double RootTwo = sqrt ( 2 ); FIXED16 RotateCos; FIXED16 RotateSin; // One of Ben's macros. It generates an error if there isn't a layer present. NEEDLAYER // Read the data from the file. CI_READDATA ( Rectangle, Rect ) // Create a new node. if ( ( pRectangle = new NodeRegularShape () ) == NULL ) return FALSE; // The major and minor axes of the NodeRegularShape correspond to the height and // width of the bounding ellipse. By multiplying half of their values by the // square root of two, the ellipse's dimensions are obtained. MajorAxis.y = ( INT32 ) ( ( double ) ( Rect.Height / 2 ) * RootTwo ); MinorAxis.x = ( INT32 ) ( ( double ) ( Rect.Width / 2 ) * RootTwo ); // Calculate the sine and cosine for the rotation matrix. RotateSin = sin ( Rect.Rotation ); RotateCos = cos ( Rect.Rotation ); // Compose the transformation matrix for the shape. RectMatrix.Compose ( RotateCos, RotateCos, -RotateSin, RotateSin, Rect.Centre ); pRectangle->SetUpShape (); // Initialise the shape node. pRectangle->SetNumSides ( 4 ); // Always four sides to a rectangle. pRectangle->SetTransformMatrix ( &RectMatrix ); // The position of the rectangle. pRectangle->SetCentrePoint ( DocCoord (0, 0) ); // Always centred at the origin. pRectangle->SetMajorAxes ( MajorAxis ); // The height of the rectangle. pRectangle->SetMinorAxes ( MinorAxis ); // The width of the rectangle. // Attempt to prepare the node for insertion into the tree. if ( !TransformNode ( pRectangle ) || !SetAttributesForNode ( pRectangle, &Rect.RenderAttributes ) || !ClipNode ( ( Node ** ) &pRectangle ) || !ApplyAttributesToNode ( pRectangle ) ) { // A problem has been encountered, so return FALSE. return FALSE; } // Add the node to the tree. Data->pCurrentLayer->AddNode( pRectangle ); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_AddGlobalTransform(void) Author: Ben_Summers (Xara Group Ltd) Created: 13/08/96 Inputs: None Returns: error flag Purpose: process a AddGlobalTransform command ********************************************************************************************/ BOOL CMXImportFilter::Process_AddGlobalTransform(void) { // get the data from the file CI_READDATA(AddGlobalTransform, gt) // make a new transform stack object CMXImportTransform *pNewTrans = new CMXImportTransform(>.TransformMatrix, TRUE); if(pNewTrans == NULL) return FALSE; // add the new object to the stack and everything happy is done for us Data->TransformStack.Push(pNewTrans); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_SetGlobalTransfo(void) Author: Ben_Summers (Xara Group Ltd) Created: 13/08/96 Inputs: None Returns: error flag Purpose: process a SetGlobalTransfo command ********************************************************************************************/ BOOL CMXImportFilter::Process_SetGlobalTransform(void) { // get the data from the file CI_READDATA(SetGlobalTransform, gt) // make a new transform stack object CMXImportTransform *pNewTrans = new CMXImportTransform(>.TransformMatrix, FALSE); if(pNewTrans == NULL) return FALSE; // add the new object to the stack and everything happy is done for us Data->TransformStack.Push(pNewTrans); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_RestoreLastGlobalTransform(void) Author: Ben_Summers (Xara Group Ltd) Created: 13/08/96 Inputs: None Returns: error flag Purpose: process a RestoreLastGlobalTransform command ********************************************************************************************/ BOOL CMXImportFilter::Process_RestoreLastGlobalTransform(void) { // just need to pop the transform off the stack, and delete it // everything else just happens. Funny, isn't it? delete Data->TransformStack.Pop(); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_DrawImage(void) Author: Ben_Summers (Xara Group Ltd) Created: 15/08/96 Inputs: None Returns: error flag Purpose: process a bitmap command ********************************************************************************************/ BOOL CMXImportFilter::Process_DrawImage(void) { NEEDLAYER // right then, load our data from this silly thingy CI_READDATA(DrawImage, db) // check to see if it's a RImage type thing if(db.ImageType != cmxDRAWIMAGE_IMAGETYPE_COLOUR) return TRUE; // can't deal with this // first of all, is it a cropped bitmap, 'cos it it is, we're going to have // to import it as a path with a bitmap fill on it if(db.ImageExtent != db.CroppingRectangle) return Process_DrawImage_Cropped(db); // do a cropped one instead // right then, let's make one of these objects... INT32 Ref = db.ImageFileReference1 - 1; if(!Data->RImages[Ref].IsRImage()) return TRUE; // can't do that either without one of the RImages KernelBitmap *pBitmap = Data->RImages[Ref].GetBitmap(this); if(pBitmap == 0) return FALSE; // wasn't converted, oh dear // create a bitmap object NodeBitmap *NewBitmap = new NodeBitmap; if((NewBitmap == NULL) || !NewBitmap->SetUpPath()) return FALSE; NewBitmap->CreateShape(db.ImageExtent); // transform it by the enclosed matrix Trans2DMatrix Transform(db.Transformation); NewBitmap->Transform(Transform); // set the reference to the bitmap NewBitmap->GetBitmapRef()->Attach(pBitmap, GetDocument()); if (NewBitmap->GetBitmap() != pBitmap) { // It didn't use the bitmap we gave it, so we can delete it delete pBitmap; } // apply a few nice attributes to it NewBitmap->ApplyDefaultBitmapAttrs(0); // invalidate the bounding rectangle NewBitmap->InvalidateBoundingRect(); // put it on the right place on the page, but don't apply attributes to it Node *pNode = NewBitmap; if(!TransformNode(pNode) || !ClipNode(&pNode)) return FALSE; // add the node Data->pCurrentLayer->AddNode(pNode); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_DrawImage_Cropped(cmxiDrawImage &db) Author: Ben_Summers (Xara Group Ltd) Created: 15/08/96 Inputs: None Returns: error flag Purpose: process a bitmap command ********************************************************************************************/ #define BITM_MOVE(px, py) {co.x = (px); co.y = (py); if(!pPath->InkPath.InsertMoveTo(co)) return FALSE;} #define BITM_LINE(px, py) {co.x = (px); co.y = (py); if(!pPath->InkPath.InsertLineTo(co)) return FALSE;} #define BITM_CLOSE {if(!pPath->InkPath.CloseSubPath()) return FALSE;} BOOL CMXImportFilter::Process_DrawImage_Cropped(cmxiDrawImage &db) { // get a nice bitmap to apply as a fill INT32 Ref = db.ImageFileReference1 - 1; if(!Data->RImages[Ref].IsRImage()) return TRUE; // can't do that either without one of the RImages KernelBitmap *pBitmap = Data->RImages[Ref].GetBitmap(this); if(pBitmap == 0) return FALSE; // wasn't converted, oh dear // create a rectangular path object... // generate a path NodePath *pPath = new NodePath; if(pPath == 0 || (!pPath->SetUpPath())) { delete pPath; return FALSE; // no room to create it } // position the new elements at the beginning of the path pPath->InkPath.FindStartOfPath(); DocCoord co, cn1, cn2; // make the rectangle shape BITM_MOVE(db.CroppingRectangle.lo.x, db.CroppingRectangle.lo.y) BITM_LINE(db.CroppingRectangle.hi.x, db.CroppingRectangle.lo.y) BITM_LINE(db.CroppingRectangle.hi.x, db.CroppingRectangle.hi.y) BITM_LINE(db.CroppingRectangle.lo.x, db.CroppingRectangle.hi.y) BITM_LINE(db.CroppingRectangle.lo.x, db.CroppingRectangle.lo.y) BITM_CLOSE // finish off the path pPath->InvalidateBoundingRect(); pPath->InkPath.IsFilled = TRUE; // set up an attribute or two Data->ObjFilled = TRUE; // set up a nice attribute for this thingy if(!SetLineColour(DocColour(COLOUR_TRANS))) return FALSE; // set a nice bitmap fill DocCoord Start = DocCoord(db.ImageExtent.lo.x, db.ImageExtent.lo.y); DocCoord End1 = DocCoord(db.ImageExtent.hi.x, db.ImageExtent.lo.y); DocCoord End2 = DocCoord(db.ImageExtent.lo.x, db.ImageExtent.hi.y); if(!SetBitmapFill(pBitmap, Start, End1, End2)) return FALSE; // apply attributes SetPathFilled(TRUE); CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = FALSE; if(!AttributeManager::ApplyBasedOnDefaults(pPath, CurrentAttrs)) return FALSE; // transform it by the enclosed matrix Trans2DMatrix Transform(db.Transformation); pPath->Transform(Transform); // put it on the right place on the page, but don't apply attributes to it Node *pNode = pPath; if(!TransformNode(pNode) || !ClipNode(&pNode)) return FALSE; // add the node Data->pCurrentLayer->AddNode(pNode); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_AddClippingRegion(void) Author: Ben_Summers (Xara Group Ltd) Created: 25/08/96 Inputs: None Returns: error flag Purpose: process a AddClippingRegion command ********************************************************************************************/ BOOL CMXImportFilter::Process_AddClippingRegion(void) { CI_READDATA(AddClippingRegion, cr) // do we need to do anything? switch(cr.RegionType) { case cmxADDCLIPREGION_TYPE_NONE: return TRUE; // nothing to do break; case cmxADDCLIPREGION_TYPE_POLYGON: break; // know what to do with these default: TRACEUSER( "Neville", _T("---- thingy. type of clipping region not supported\n")); // The following wasn't here before 5/11/97, causes access violations on 611.cmx // as the pPolygon has not been allocated or has been deleted! // This is not suprising as the other types do not define it! return TRUE; // nothing to do break; } // OK, we've got a polygon type path to deal with -- do we need to intersect or not BOOL Intersect = TRUE; if(cr.ClipMode == cmxADDCLIPREGIOM_MODE_COPY) Intersect = FALSE; // make a new stack item CMXImportClipper *pClipper = new CMXImportClipper(cr.Spec.pPolygon, Intersect); if(pClipper == NULL) return FALSE; // error // and add it to the silly stack if(!Data->ClipperStack.Push(pClipper)) return FALSE; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_RemoveLastClippingRegion(void) Author: Ben_Summers (Xara Group Ltd) Created: 25/08/96 Inputs: None Returns: error flag Purpose: process a RemoveLastClippingRegion command ********************************************************************************************/ BOOL CMXImportFilter::Process_RemoveLastClippingRegion(void) { // remove the last item from the clipper stack if(Data->ClipperStack.GetCount() > 0) delete Data->ClipperStack.Pop(); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_ClearClipping(void) Author: Ben_Summers (Xara Group Ltd) Created: 26/08/96 Inputs: None Returns: error flag Purpose: process a ClearClipping command ********************************************************************************************/ BOOL CMXImportFilter::Process_ClearClipping(void) { // go through removing all clipping while(Data->ClipperStack.GetCount() != 0) { delete Data->ClipperStack.Pop(); } return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_EndSection(void) Author: Ben_Summers (Xara Group Ltd) Created: 26/08/96 Inputs: None Returns: error flag Purpose: process a EndSection command ********************************************************************************************/ BOOL CMXImportFilter::Process_EndSection(void) { Data->EndSectionFound = TRUE; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_(void) Author: Ben_Summers (Xara Group Ltd) Created: 13/08/96 Inputs: None Returns: error flag Purpose: process a command ********************************************************************************************/ /* BOOL CMXImportFilter::Process_(void) { return TRUE; } */ /******************************************************************************************** > BOOL CMXImportFilter::Process_BeginTextStream(void) Author: Claude_Quemerais (Xara Group Ltd) Created: 14/08/96 Inputs: None Returns: error flag Purpose: process a text command, create a text story and set up its width. ********************************************************************************************/ BOOL CMXImportFilter::Process_BeginTextStream(void) { CI_READDATA(BeginTextStream, text) TRACEUSER( "Claude", _T("BeginTextStream")); // Take the top corner of the text's bbox as place to start the text DocCoord Pos = text.BBox.hi;//HighCorner(); // create the empty text story Data->pTextStory = TextStory::CreateTextObject(Pos); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_TextFrame(void) Author: Claude_Quemerais (Xara Group Ltd) Created: 15/08/96 Inputs: None Returns: error flag Purpose: Put the text in the right place (it was first in a CMX's default place) using ********************************************************************************************/ BOOL CMXImportFilter::Process_TextFrame(void) { TRACEUSER( "Claude", _T("TextFrame")); CI_READDATA(TextFrame, textf) // if(!Data->TextFrameRead) // { Data->TextFrameRead = TRUE; INT32 TextWidth = 70000; // The width of the text story for(INT32 i = 0 ; i < textf.columns.count ; i++) { TextWidth += textf.columns.columns[i]; TextWidth += textf.columns.gutters[i]; } // Set the width of the text story. In MILLIPOINT! Data->pTextStory->SetImportFormatWidth((INT32)(TextWidth * Data->BaseScaleFactor)); // Set the matrix of the text story Data->pTextStory->SetStoryMatrix(textf.Mat); // Clean up the place delete textf.columns.columns; delete textf.columns.gutters; // } return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_Characters(void) Author: Claude_Quemerais (Xara Group Ltd) Created: 19/08/96 Inputs: None Returns: error flag Purpose: Put the characters in the story ********************************************************************************************/ BOOL CMXImportFilter::Process_Characters(void) { CI_READDATA(Characters, fabbyChars) // Create an empty line Data->pTextLine = Data->pTextStory->FindLastLine(); SetNonTextAttributeIgnore(); if (!AttributeManager::ApplyBasedOnDefaults(Data->pTextLine, CurrentAttrs)) { delete Data->pTextLine; Data->pTextLine = NULL; } SetNonTextAttributeNotIgnore(); for(INT32 i = 0 ; i < fabbyChars.ch.count ; i++) { BOOL Ignore = FALSE; TRACEUSER( "Claude", _T("Character %d is %c\n"), i, fabbyChars.ch.characters[i]); if(fabbyChars.ch.characters[i] < 32) { if(fabbyChars.ch.characters[i] == 13) { // End of line to skip and create a new line // Create an empty line Data->pTextLine = TextLine::CreateEmptyTextLine(Data->pTextStory, LASTCHILD); SetNonTextAttributeIgnore(); if (!AttributeManager::ApplyBasedOnDefaults(Data->pTextLine, CurrentAttrs)) { delete Data->pTextLine; Data->pTextLine = NULL; } SetNonTextAttributeNotIgnore(); Ignore = TRUE; } else if(fabbyChars.ch.characters[i] == 9) fabbyChars.ch.characters[i] = 32; else // Ignore the bad characters. Ignore = TRUE; } if(!Ignore) { // Use last text line VisibleTextNode* pLastNode = Data->pTextLine->FindLastVTN(); ERROR2IF(pLastNode == NULL, NULL, "Empty Story"); // Create a new TextChar VisibleTextNode* pNew = new TextChar(pLastNode, PREV, fabbyChars.ch.characters[i]); if (pNew != NULL) { // UMASK used to determine if this character has any attributes // different from default. // If so set them INT32 UMASK = 0; if(!CorelDraw7) { if(Data->NumCharInfo != 0) UMASK = Data->CharInfos[fabbyChars.ch.indices[i]].UsageMask; } else { if(fabbyChars.ch.indices[i] != cmxMaxValueWORD) UMASK = Data->CharInfos[fabbyChars.ch.indices[i]].UsageMask; } if(((UMASK & cmxUSAGEMASK_UseTypeNum) != 0) || ((UMASK & cmxUSAGEMASK_UseTypeStyle) != 0)) { INT32 fontRef = Data->CharInfos[fabbyChars.ch.indices[i]].FontRef-1; String_64 name((TCHAR*)*Data->Fonts[fontRef].mFont); SetTextTypeFace(&name); SetTextItalic(Data->Fonts[fontRef].mIsItalic); SetTextBold(Data->Fonts[fontRef].mIsBold); } if((UMASK & cmxUSAGEMASK_UseTypeSize) != 0) // Set up the size of the font SetTextSize(Data->CharInfos[fabbyChars.ch.indices[i]].TypeSize); if(((UMASK & cmxUSAGEMASK_UseCharFill) != 0) || ((UMASK & cmxUSAGEMASK_UseCharOutline) != 0)) // Apply specific attributes SetAttributesForNode(pNew, &Data->CharInfos[fabbyChars.ch.indices[i]].RenderAttributes, FALSE); else // Apply default attributes SetAttributesForNode(pNew, &Data->textRenderAttributes, FALSE); if (!AttributeManager::ApplyBasedOnDefaults(pNew, CurrentAttrs)) { delete pNew; pNew = NULL; } // Set the default back to what they were! String_64 name((TCHAR*)*Data->Fonts[Data->currentRef].mFont); SetTextTypeFace(&name); SetTextItalic(Data->Fonts[Data->currentRef].mIsItalic); SetTextBold(Data->Fonts[Data->currentRef].mIsBold); SetTextSize(Data->currentSize); } } } // Clean all up delete fabbyChars.ch.characters; delete fabbyChars.ch.indices; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_CharInfo(void) Author: Claude_Quemerais (Xara Group Ltd) Created: 19/08/96 Inputs: None Returns: error flag Purpose: Put the characters in the story ********************************************************************************************/ BOOL CMXImportFilter::Process_CharInfo(void) { CI_READDATA(CharInfo, ci) // Get the info from the CharInfo Data->NumCharInfo++; Data->CharInfos[Data->NumCharInfo-1].UsageMask = ci.UsageMask; Data->CharInfos[Data->NumCharInfo-1].FontRef = ci.FontRef; Data->CharInfos[Data->NumCharInfo-1].TypeSize = ci.TypeSize; Data->CharInfos[Data->NumCharInfo-1].CharAngle = ci.CharAngle; Data->CharInfos[Data->NumCharInfo-1].RenderAttributes = ci.RenderAttributes; Data->CharInfos[Data->NumCharInfo-1].HShift = ci.HShift; Data->CharInfos[Data->NumCharInfo-1].VShift = ci.VShift; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_BeginParagraph(void) Author: Claude_Quemerais (Xara Group Ltd) Created: 21/08/96 Inputs: None Returns: error flag Purpose: Add the attributes to the text ********************************************************************************************/ BOOL CMXImportFilter::Process_BeginParagraph(void) { SetTextAttributeNotIgnore(); CI_READDATA(BeginParagraph, Paragraph) // Get the correct font reference Data->currentRef = Paragraph.FontRef-1; // And font size Data->currentSize = Paragraph.FontSize; // Set the font String_64 name((TCHAR*)*Data->Fonts[Paragraph.FontRef-1].mFont); SetTextTypeFace(&name); // Set the text attributes to whatever they need to be SetTextItalic(Data->Fonts[Paragraph.FontRef-1].mIsItalic); SetTextBold(Data->Fonts[Paragraph.FontRef-1].mIsBold); SetTextSize(Paragraph.FontSize); switch(Paragraph.Justification) { case cmxNoAlignment: // Some Corel sillyness, put it Left Justified // as it's what it looks like anyway. Data->textJustification = JLEFT; break; case cmxLeftJustification: Data->textJustification = JLEFT; break; case cmxCenterJustification: Data->textJustification = JCENTRE; break; case cmxRightJustification: Data->textJustification = JRIGHT; break; case cmxFullJustification: Data->textJustification = JFULL; break; case cmxForceJustification: Data->textJustification = JFULL; break; default: // no worries here. break; } SetTextJustification(Data->textJustification); // Set the indentation for the text story Data->pTextStory->SetLeftIndent((INT32)(Paragraph.LeftMargin * Data->BaseScaleFactor)); Data->pTextStory->SetRightIndent((INT32)(Paragraph.RightMargin * Data->BaseScaleFactor)); // Save the rendering attributes to use them latter Data->textRenderAttributes = Paragraph.RenderAttributes; return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_EndParagraph(void) Author: Claude_Quemerais (Xara Group Ltd) Created: 14/08/96 Inputs: None Returns: error flag Purpose: end the paragraph, set the text attributes to be ignored again ********************************************************************************************/ BOOL CMXImportFilter::Process_EndParagraph(void) { // Set the text attributes back to be ignored SetTextAttributeIgnore(); return TRUE; } /******************************************************************************************** > BOOL CMXImportFilter::Process_EndTextStream(void) Author: Claude_Quemerais (Xara Group Ltd) Created: 14/08/96 Inputs: None Returns: error flag Purpose: end the text thingy, puting things in the right place, and addig the node node. ********************************************************************************************/ BOOL CMXImportFilter::Process_EndTextStream(void) { Data->TextFrameRead = FALSE; // Make the text story as a node Node *pNode = Data->pTextStory; if( !TransformNode(pNode) || !ClipNode(&pNode))// || // !ApplyAttributesToNode(pNode)) // Don't apply the attributes again because that's bad! return FALSE; // add the node Data->pCurrentLayer->AddNode(pNode); return TRUE; }