cmxifltr.cpp

Go to the documentation of this file.
00001 // $Id: cmxifltr.cpp 1282 2006-06-09 09:46:49Z alex $
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 // CMX import Filter
00099 
00100 
00101 #include "camtypes.h"
00102 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00103 //#include "filtrres.h"
00104 //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 #include "page.h"
00106 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "tim.h"
00108 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "nodepath.h"
00110 #include "riffform.h"
00111 #include "progress.h"
00112 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "layer.h"
00114 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 #include "cdrfiltr.h"
00116 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 #include "combshps.h"
00118 #include "nodetxts.h"
00119 #include "attrmap.h"
00120 
00121 #include "cmxform.h"
00122 #include "cmxifltr.h"
00123 #include "cmxistut.h"
00124 #include "cmxibits.h"
00125 //#include "cmxres.h"
00126 #include "cmxidata.h"
00127 #include "cmxibitm.h"
00128 
00129 CC_IMPLEMENT_DYNAMIC(CMXImportFilter, VectorFilter)
00130 CC_IMPLEMENT_DYNAMIC(CMXImportFilterDataSet, CCObject)
00131 
00132 #define new CAM_DEBUG_NEW
00133 
00134 #ifdef _DEBUG
00135 void CMXImportFilter::FormatErrorBreakingFunction(void)
00136 {
00137     TRACEUSER( "Ben", _T(">>> format error in cmx file\n"));
00138 }
00139 #endif
00140 
00141 /********************************************************************************************
00142 
00143 >   CMXImportFilter::CMXImportFilter()
00144 
00145     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00146     Created:    05/08/96
00147     Inputs:     None
00148     Returns:    None
00149     Purpose:    Constructor for class CMXImportFilter
00150     SeeAlso:    class VectorFilter
00151 
00152 ********************************************************************************************/
00153 
00154 CMXImportFilter::CMXImportFilter()
00155 {
00156     // Set up filter descriptions.
00157     FilterName.Load(_R(IDT_CMXIMPORTFILTER_FILTERNAME));
00158     FilterInfo.Load(_R(IDT_CMXIMPORTFILTER_FILTERINFO));
00159     FilterID = FILTERID_CMXIMPORT;
00160 
00161     Flags.CanImport = TRUE;
00162     Flags.CanExport = FALSE;
00163 
00164     ImportMsgID = _R(IDT_IMPORTMSG_CMX);
00165 
00166     ExportMsgID = _R(IDT_EXPORTMSG_CMX);
00167 
00168     // set up the info
00169     CMXIinfo::SetUpInfo();
00170 
00171     // mark the data set as not being used
00172     Data = NULL;
00173 
00174     //  By default we're not dealing with a file from CorelDraw 7
00175     CorelDraw7  =   FALSE;
00176 }
00177 
00178 /********************************************************************************************
00179 
00180 >   BOOL CMXImportFilter::Init()
00181 
00182     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00183     Created:    05/08/96
00184     Inputs:     None
00185     Returns:    BOOL, propably saying whether we succeeded or not, buts it not documented
00186     Purpose:    Initialiser for class CMXImportFilter
00187     SeeAlso:    Filter
00188 
00189 ********************************************************************************************/
00190 
00191 BOOL CMXImportFilter::Init()
00192 {
00193     // Get the OILFilter object
00194     pOILFilter = new CMXImportOILFilter(this);
00195     if (pOILFilter == NULL)
00196         return FALSE;
00197 
00198     
00199     return TRUE;
00200 }
00201 
00202 /********************************************************************************************
00203 
00204 >   INT32 CMXImportFilter::HowCOmpatible(PathName& Filename,
00205                             ADDR HeaderStart,
00206                             UINT32 HeaderSize,
00207                             UINT32 FileSize);
00208 
00209     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00210     Created:    05/08/96
00211     Inputs:     Filename - filename of file to check
00212                 HeaderStart, HeaderSize, - infomation on header of file loaded into memory
00213                 FileSize - length of file (bytes)
00214     Returns:    0 to 10. 0 means I know nothing about this file, 10 means its definitly mine
00215     Purpose:    Looks at the start of the file to see if we recognise it as one of ours
00216     SeeAlso:    class Filters, class CDRFilter
00217 
00218 ********************************************************************************************/
00219 
00220 INT32 CMXImportFilter::HowCompatible(PathName & FileName, ADDR HeaderStart, UINT32 HeaderSize, UINT32 FileSize)
00221 {
00222     // see if we're a nice CMX file...
00223 PORTNOTE("byteorder", "TODO: Check byte ordering")
00224     RIFFFile_Header *pHdr = (RIFFFile_Header *)HeaderStart;
00225 
00226     if(pHdr->CK.ckID == RIFFTYPE_RIFF)
00227     {
00228         switch(pHdr->FormType)
00229         {
00230         case cmxRIFFFORMTYPE_CMX:
00231             // yep, it's one of ours
00232             return 10;
00233             break;
00234 
00235         case cmxRIFFFORMTYPE_CDR5:
00236         case cmxRIFFFORMTYPE_CDT5:
00237         case cmxRIFFFORMTYPE_CDR6:
00238         case cmxRIFFFORMTYPE_CDT6:
00239             // Tootle through the file if it's a CDR file to see if we
00240             // can't load that nice CMX file it might have inside it.
00241             if(CDRFilter::HasCDRFileGotCMXFile(&FileName))
00242             {
00243                 return 10;          // we'll have that too, then
00244             }
00245             break;
00246 
00247         default:
00248             break;
00249         }
00250     }
00251 
00252     return 0;
00253 }
00254 
00255 /********************************************************************************************
00256 
00257 >   BOOL CMXImportFilter::DoImport(SelOperation * Op, CCLexFile * pDiskFile,
00258                             Document * DestDoc, BOOL AutoChoosen , ImportPosition * Pos,
00259                             KernelBitmap** ppImportedBitmap, DocCoord* pPosTranslate, String_256* URL)
00260 
00261     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00262     Created:    05/08/96
00263     Inputs:     Op - pointer to the operatioj that this input process is associated with,
00264                 pDiskFile - the CMXImport file to be loaded
00265                 DestDoc - the document object whcih should hold the data read in from this file
00266                 URL - original URL of the imported file
00267     Returns:    TRUE is the input operation worked, FALSE if not
00268     Purpose:    Read an CMXImport format file and convert it into Camelot tree data structures. When
00269                 the file is loaded we force a redraw for the area affected by the new data
00270                 At the moment the data is just put on the first layer of the first spread
00271                 of the first chapter in the document, and this is a bodge.
00272                 The operation is terminated (i.e. its End() function is called) if the
00273                 operation completed successfully.
00274     Errors:     Fails (returns FALSE) if the document structure is incorrect, if the CMXImport file
00275                 contains a syntax error, of the CMXImport file cannot be found/opened or if its
00276                 not actually an CMXImport file.
00277     SeeAlso:    CMXImportFilter::HowCompatible
00278 
00279 ********************************************************************************************/
00280 
00281 BOOL CMXImportFilter::DoImport(SelOperation * Op, CCLexFile * pDiskFile,
00282                             Document * DestDoc, BOOL AutoChoosen , ImportPosition * Pos,
00283                             KernelBitmap** ppImportedBitmap, DocCoord* pPosTranslate, String_256* URL)
00284 {
00285     // set variables
00286     pFile = pDiskFile;
00287     Is32Bit = FALSE;            // for now... Stage1_ReadHeader sets it properly
00288     StartPosition = 0;
00289     TheDocument = DestDoc;
00290 
00291     // create a dataset
00292     ERROR3IF(Data != NULL, "CMX data set already created");
00293     Data = new CMXImportFilterDataSet(this);
00294     if(Data == NULL)
00295         return FALSE;
00296 
00297     // set up various filter type things
00298     Data->pProgress = new Progress(_R(IDT_CMX_IMPORTMSG), 1, FALSE);
00299     if(Data->pProgress == NULL)
00300         return FALSE;
00301     if(!SetUpCurrentAttrs())
00302         return FALSE;
00303 
00304     //  We haven't read the text frame yet
00305     Data->TextFrameRead = FALSE;
00306     
00307     SetTextAttributeIgnore();
00308 
00309     // get the spread we're using
00310     Document *pTheDocument = GetDocument();
00311     ERROR2IF(pTheDocument == NULL, FALSE, "no document for filter");
00312     Spread *pSpread = NULL; //pTheDocument->GetSelectedSpread();
00313 
00314     if (Pos == NULL)
00315     {       
00316         // For now, position objects on 1st page of spread 1
00317         pSpread = GetFirstSpread(DestDoc);
00318         Page *pPage = (Page *) pSpread->FindFirstPageInSpread();
00319         ENSURE(pPage->IsKindOf(CC_RUNTIME_CLASS(Page)),
00320                "MetaFileFilter::DoImport(): Could not find first Page");
00321     }
00322     else
00323     {
00324         pSpread = Pos->pSpread;
00325     }
00326 
00327 
00328     // do various bits and pieces to convert that silly file
00329     BOOL EverythingWentSwimmingly = TRUE;
00330     TRY
00331     {
00332         if(     !Stage1_ReadHeader(pSpread)
00333             ||  !Stage2_ReadMasterIndex()
00334             ||  !Stage3_ConvertDescriptionSections()
00335             ||  !Stage4_ConvertPage()
00336             ||  !Stage5_PlaceObjectsInTree(pSpread, Op, Pos) )
00337             EverythingWentSwimmingly = FALSE;
00338     }
00339     CATCH(CFileException, e)
00340     {
00341         // something went wrong -- clean up
00342         CleanUpAfterImport();
00343 
00344         return FALSE;
00345     }
00346     END_CATCH
00347 
00348     CleanUpAfterImport();
00349 
00350     return EverythingWentSwimmingly;
00351 }
00352 
00353 
00354 /********************************************************************************************
00355 
00356 >   void CMXImportFilter::CleanUpAfterImport(void)
00357 
00358     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00359     Created:    07/08/96
00360     Inputs:     None
00361     Returns:    nothin' mate
00362     Purpose:    Cleans everything up after a sucessful or non-sucessful import
00363 
00364 ********************************************************************************************/
00365 
00366 void CMXImportFilter::CleanUpAfterImport(void)
00367 {
00368     // delete the data set -- that class will take care of itself and delete everything
00369     // necessary to ensure we don't leak anything
00370     if(Data != NULL)
00371         delete Data;
00372 
00373     Data = NULL;
00374 
00375     // vape attributes
00376     DeleteCurrentAttrs();
00377 }
00378 
00379 
00380 /********************************************************************************************
00381 
00382 >   BOOL CMXImportFilter::LocateRootLevelRIFFSection(DWORD Section)
00383 
00384     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00385     Created:    07/08/96
00386     Inputs:     None
00387     Returns:    TRUE if the section was fount
00388     Purpose:    Sets the file pointer to the start of the data in the specified
00389                 RIFF section. Doesn't go into lists.
00390 
00391 ********************************************************************************************/
00392 
00393 BOOL CMXImportFilter::LocateRootLevelRIFFSection(DWORD Section)
00394 {
00395     // go to the beginning of the file
00396     Seek(0);
00397 
00398     // read in the file header, and check it's a riff file
00399     RIFFFile_Header Hdr;
00400     pFile->read(&Hdr, sizeof(Hdr));
00401 
00402     if(Hdr.CK.ckID != RIFFTYPE_RIFF)
00403         return FALSE;           // file is not a riff form
00404 
00405     UINT32 loc = sizeof(Hdr);
00406 
00407     // run through the thingys
00408     while(loc < Hdr.CK.ckSize)
00409     {
00410         RIFFck ck;
00411         pFile->read(&ck, sizeof(ck));
00412         loc += sizeof(ck);
00413         if(ck.ckID == Section)
00414             return TRUE;            // found it!
00415 
00416         // skip to start of next chunk
00417         loc += ck.ckSize;
00418         Seek(loc);
00419     }
00420 
00421     return FALSE;
00422 }
00423 
00424 
00425 /********************************************************************************************
00426 
00427 >   BOOL CMXImportFilter::Stage1_ReadHeader(Spread *pSpread)
00428 
00429     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00430     Created:    07/08/96
00431     Inputs:     None
00432     Returns:    error flag
00433     Purpose:    Reads the header from the file, and sets various internal variables to
00434                 reflect what it found there. It creates the base matrix for transforming
00435                 stuff.
00436 
00437 ********************************************************************************************/
00438 
00439 BOOL CMXImportFilter::Stage1_ReadHeader(Spread *pSpread)
00440 {
00441     // find the header of the file
00442     if(!LocateRootLevelRIFFSection(cmxRIFFCI_Header))
00443     {
00444         // OK, didn't find one of those... see if we can get a CMX one instead
00445         if(LocateRootLevelRIFFSection(cmxRIFFFORMTYPE_cmx1))
00446         {
00447             // fine... alter the thingy to point to the beginning of this section
00448             StartPosition = pFile->tellIn();
00449             // and locate the header section
00450             if(!LocateRootLevelRIFFSection(cmxRIFFCI_Header))
00451             {
00452                 CMXFORMATERROR(FALSE)
00453             }
00454         }
00455         else
00456         {
00457             CMXFORMATERROR(FALSE)
00458         }
00459     }
00460 
00461     // read it in
00462     CI_READDATA(FileHeader, Hdr)
00463 
00464     // check that the id is correct
00465     if(strcmp(Hdr.ID, cmxID) != 0)
00466         CMXFORMATERROR(FALSE)       // wasn't a CMX file
00467 
00468     // read the handy bits from it
00469     switch(Hdr.CoordSize & 0xf)
00470     {
00471     case cmxCOORDSIZE_32:
00472         TRACEUSER( "Ben", _T("\n\n********************** 32 bit CMX file\n"));
00473         Is32Bit = TRUE;
00474         break;
00475 
00476     case cmxCOORDSIZE_16:
00477         TRACEUSER( "Ben", _T("\n\n********************** 16 bit CMX file\n"));
00478         Is32Bit = FALSE;
00479         break;
00480 
00481     default:
00482         // don't understand this data size
00483         CMXFORMATERROR(FALSE);
00484         break;
00485     }
00486 
00487     // set the location of the index
00488     Data->IndexFilePosition = Hdr.IndexSection;
00489 
00490     // set up the base matrix for transformation of the objects on the page
00491     Page *pPage = (Page *)pSpread->FindFirstPageInSpread();
00492 
00493     // Use bottom left of page as origin as in CMX in (0,0) is the centre of the page
00494     DocRect PageRect = pPage->GetPageRect();
00495     DocCoord Origin = DocCoord(PageRect.lo.x + (PageRect.Width() / 2),
00496             PageRect.lo.y + (PageRect.Height() / 2));
00497 
00498     // set a matrix which transforms things appropriately
00499     double Scale;
00500     if(Is32Bit)
00501     {
00502         Scale = 1 / CAMCOORD_SCALEFACTOR32;
00503     }
00504     else
00505     {
00506         Scale = 72;
00507     }
00508     Matrix TheMat = Matrix((FIXED16)Scale, (FIXED16)Scale);
00509 
00510     // transform the coordinates
00511     TheMat *= Matrix(Origin);
00512     
00513     // set the matrix
00514     Data->BaseMatrix = TheMat;
00515     Data->BaseScaleFactor = Scale;
00516 
00517     // and set the current matrix pointer to it
00518     Data->pCurrentMatrix = &Data->BaseMatrix;
00519 
00520     return TRUE;
00521 }
00522 
00523 
00524 /********************************************************************************************
00525 
00526 >   BOOL CMXImportFilter::Stage5_PlaceObjectsInTree(Spread *pSpread, SelOperation *pOp, ImportPosition *pPos)
00527 
00528     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00529     Created:    07/08/96
00530     Inputs:     None
00531     Returns:    error flag
00532     Purpose:    sticks the objects in the document tree
00533 
00534 ********************************************************************************************/
00535 
00536 BOOL CMXImportFilter::Stage5_PlaceObjectsInTree(Spread *pSpread, SelOperation *pOp, ImportPosition *pPos)
00537 {
00538     Trans2DMatrix Xlate;
00539     BOOL Translate = FALSE;
00540     Coord Offset;
00541 
00542     // do we need to do a drag and drop translation?
00543     if(GetDragAndDropTranslation(pPos, Data->AllObjectsBoundsRect, &Offset))
00544     {
00545         Translate = TRUE;
00546         Xlate = Trans2DMatrix(Offset.x, Offset.y);
00547     }
00548 
00549     BOOL ImportingWithLayers = FALSE;
00550 
00551     // do we want to import with layers?
00552 #ifdef WEBSTER
00553     // In Webster, just use the default preference settings as these should be set to
00554     // ImportWithLayers to False.
00555     if (
00556         (!TheDocument->IsImporting() && Filter::OpenWithLayers) ||
00557         (TheDocument->IsImporting() && Filter::ImportWithLayers)
00558         )
00559         ImportingWithLayers = TRUE;
00560 #else
00561     // In Camelot, we must check to see if the document is being imported and if so if
00562     // there are any frames present. If there are then don't use layers, if there are
00563     // then use the preference setting.
00564     if (TheDocument->IsImporting())
00565     {
00566         Spread * pTheSpread = TheDocument->GetSelectedSpread();
00567         Layer * pFrame = NULL;
00568         if (pTheSpread != NULL)
00569             pFrame = pTheSpread->FindFirstFrameLayer();
00570         if (pFrame != NULL)
00571             ImportingWithLayers = FALSE;                    // Frames present so do not import layers
00572         else
00573             ImportingWithLayers = Filter::ImportWithLayers; // No frames so use the preference setting
00574     }
00575     else
00576     {
00577         ImportingWithLayers = Filter::OpenWithLayers;
00578     }
00579 #endif
00580 
00581     NodeGroup *pGroup = NULL;
00582     if(!ImportingWithLayers)
00583     {
00584         if((pGroup = new NodeGroup) == NULL)
00585             return FALSE;
00586     }
00587 
00588     // go through the layer list adding stuff
00589     CMXImportLayer *pSarah = (CMXImportLayer *)Data->Layers.GetHead();
00590     while(pSarah != NULL)
00591     {
00592         ERROR2IF(!IS_A(pSarah, CMXImportLayer), FALSE, "thingy not a CMX import layer");
00593 
00594         if(ImportingWithLayers)
00595         {
00596             // get the layer, and mark the import layer as used
00597             Layer *pNewLayer = pSarah->UseSubTreeAsLayer();
00598             if(pNewLayer == NULL)
00599                 return FALSE;
00600 
00601             // and maybe translate it a bit
00602             if(Translate)
00603                 pNewLayer->Transform(Xlate);
00604 
00605             // insert the layer into the document
00606             if(!pOp->DoInsertNewNode(pNewLayer, (Node *)pSpread, LASTCHILD, TRUE))
00607             {
00608                 // It didn't work - delete the sub-tree we just created
00609                 pNewLayer->CascadeDelete();
00610                 delete pNewLayer;
00611                 return FALSE;
00612             }
00613 
00614             // make sure it's name is unique
00615             pNewLayer->EnsureUniqueLayerID();                   
00616             
00617             // ... and finally optimise it's attributes
00618             if(!pNewLayer->OptimiseAttributes())
00619                 return FALSE;
00620         }
00621         else
00622         {
00623             // do stuff without layers
00624             ERROR3IF(pGroup == NULL, "no group node created");
00625 
00626             // get the subtree of the layer, and add it
00627             if(pSarah->GetSubTree() != NULL)    // some may be empty
00628             {
00629                 Node *pSubTree = pSarah->GetSubTree();
00630                 // add it to the group node
00631                 pSubTree->InsertChainSimple(pGroup, LASTCHILD);
00632             }
00633 
00634             // mark the layer as being used
00635             pSarah->UseSubTree();
00636         }
00637 
00638         pSarah = (CMXImportLayer *)Data->Layers.GetNext(pSarah);
00639     }
00640 
00641     if(ImportingWithLayers)
00642     {
00643         // get the insertation node set up
00644         TheDocument->ResetInsertionPosition();
00645     }
00646     else
00647     {
00648         // Make sure that there is a layer to put the bitmap onto
00649         if (!MakeSureLayerExists(TheDocument))
00650             // There is no layer and one could not be made, so we will have to fail
00651             return FALSE;
00652 
00653     //  TheDocument->ResetInsertionPosition();
00654         // check to see if the group node has more than one child
00655         // if it doesn't just insert the child and not the group, and then
00656         // delete the group node afterwards
00657         NodeRenderableBounded *InsertNode = pGroup;
00658 
00659         NodeRenderableBounded *FirstChild = (NodeRenderableBounded *)pGroup->FindFirstChild();
00660 
00661         if(FirstChild != 0)
00662         {
00663             // if the first child hasn't got a sibling, then there's only one
00664             // child to the group, so just insert the child
00665             if(FirstChild->FindNext() == 0)
00666                 InsertNode = FirstChild;
00667         }
00668 
00669         // bit of translation for sir?
00670         if(Translate)
00671             InsertNode->Transform(Xlate);
00672 
00673         // if there isn't a group, detach it
00674         if(InsertNode != pGroup)
00675             InsertNode->UnlinkNodeFromTree(NULL);
00676 
00677         // invalidate the insert node's bounds
00678         InsertNode->InvalidateBoundingRect();
00679 
00680         // put the group into the document
00681         if (!pOp->DoInsertNewNode(InsertNode, pSpread, TRUE))
00682         {
00683             // It didn't work - delete the sub-tree we just created
00684             pGroup->CascadeDelete();
00685             delete pGroup;
00686             return FALSE;
00687         }
00688 
00689         // optimise the groups attributes
00690         if(!InsertNode->OptimiseAttributes())
00691             return FALSE;
00692 
00693         // delete the group if it wasn't used
00694         if(InsertNode != pGroup)
00695             delete pGroup;
00696     }
00697 
00698     // add colours
00699     if(!AddColoursToDocument())
00700         return FALSE;
00701 
00702     // do a quick post import on it
00703     TheDocument->PostImport();
00704     
00705     return TRUE;
00706 }
00707 
00708 
00709 /********************************************************************************************
00710 
00711 >   CMXImportFilterDataSet::CMXImportFilterDataSet(CMXImportFilter *pFilter)
00712 
00713     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00714     Created:    07/08/96
00715     Inputs:     none
00716     Returns:    none
00717     Purpose:    constructor for the CMX import filter's data set
00718 
00719 ********************************************************************************************/
00720 
00721 CMXImportFilterDataSet::CMXImportFilterDataSet(CMXImportFilter *pFilter)
00722     : TransformStack(cmxiSTACKTYPE_TRANSFORM, pFilter)
00723     , ClipperStack(cmxiSTACKTYPE_CLIPPER, pFilter)
00724 {
00725     // mark all index entry positions as not present
00726     for(INT32 l = 0; l < cmxMASTERIN_MAXENTRY; l++)
00727         MasterIndexEntries[l] = 0;
00728 
00729     // set things to null
00730     pProgress = NULL;
00731     CommandsInPage = -1;
00732     pCurrentLayer = NULL;
00733     pCurrentMatrix = NULL;
00734     pTextStory = NULL;
00735     pTextLine = NULL;
00736     NumColours = 0;
00737     Colours = NULL;
00738     NumOutlines = 0;
00739     Outlines = NULL;
00740     NumPens = 0;
00741     Pens = NULL;
00742     BaseScaleFactor = 0;
00743     NumLineStyles = 0;
00744     LineStyles = NULL;
00745     NumRImages = 0;
00746     RImages = NULL;
00747     NumProcedures = 0;
00748     Procedures = NULL;
00749     NumDotDashes = 0;
00750     DotDashes = NULL;
00751     pClippingPath = NULL;
00752     NumArrowShapes = 0;
00753     ArrowShapes = NULL;
00754     NumArrowheads = 0;
00755     Arrowheads = NULL;
00756     NumBitmaps = 0;
00757     Bitmaps = NULL;
00758     NumFonts    =   0;
00759     Fonts   =   NULL;
00760     //  No way to know how many CharInfo are going to be there before actually read them
00761     //  Use a number big enough. NumCharInfo will be the actual number.
00762     NumCharInfo =   0;
00763     CharInfos = new cmxiCharInfo[100];
00764     for(INT32 i = 0 ; i < 100 ; i++)
00765         CharInfos[i].UsageMask  =   0;
00766 
00767 
00768 
00769     // flags
00770     InPage = FALSE;
00771     RemoveLens = FALSE;
00772     EndSectionFound = FALSE;
00773     HaveFirstObjInBoundsRect = FALSE;
00774 
00775     // counts of approxed objects
00776     AttributesApproximated = 0;
00777     ObjectsApproximated = 0;
00778     ClippingsApproximated = 0;
00779 }
00780 
00781 
00782 /********************************************************************************************
00783 
00784 >   CMXImportFilterDataSet::~CMXImportFilterDataSet()
00785 
00786     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00787     Created:    07/08/96
00788     Inputs:     none
00789     Returns:    none
00790     Purpose:    destructor for the CMX import filter's data set -- it will delete all
00791                 objects which aren't needed after import.
00792 
00793 ********************************************************************************************/
00794 
00795 CMXImportFilterDataSet::~CMXImportFilterDataSet()
00796 {
00797     // delete list entries -- they will delete their contents if they haven't been used
00798     Layers.DeleteAll();
00799     
00800     // close down the progress system
00801     if(pProgress != NULL)
00802     {
00803         delete pProgress;
00804         pProgress = NULL;
00805     }
00806 
00807     // delete lists of stuff
00808     if(Colours != 0)
00809         delete [] Colours;
00810     if(Outlines != 0)
00811         delete [] Outlines;
00812     if(Pens != 0)
00813         delete [] Pens;
00814     if(LineStyles != 0)
00815         delete [] LineStyles;
00816     if(RImages != 0)
00817         delete [] RImages;
00818     if(Procedures != 0)
00819         delete [] Procedures;
00820     if(DotDashes != 0)
00821         delete [] DotDashes;
00822     if(ArrowShapes != 0)
00823         delete [] ArrowShapes;
00824     if(Arrowheads != 0)
00825         delete [] Arrowheads;
00826     if(Bitmaps != 0)
00827         delete [] Bitmaps;
00828     if(Fonts != 0)
00829         delete [] Fonts;
00830     if(CharInfos != 0)
00831         delete [] CharInfos;
00832 }
00833 
00834 
00835 // access functions to avoid adding cmxidata.h to cmxifltr.h
00836 void CMXImportFilter::AttributeApproximated(void) {Data->AttributesApproximated++;}
00837 void CMXImportFilter::ClippingApproximated(void) {Data->ClippingsApproximated++;}
00838 void CMXImportFilter::ObjectApproximated(void) {Data->ObjectsApproximated++;}
00839 Matrix *CMXImportFilter::GetBaseMatrix(void) {return &Data->BaseMatrix;};
00840 Matrix *CMXImportFilter::GetCurrentMatrix(void) {return Data->pCurrentMatrix;};
00841 void CMXImportFilter::SetMatrix(Matrix *pNewMatrix) {Data->pCurrentMatrix = pNewMatrix;};
00842 void CMXImportFilter::SetClippingPath(Path *pClipper) {Data->pClippingPath = pClipper;};
00843 
00844 
00845 /********************************************************************************************
00846 
00847 >   BOOL CMXImportFiler::TransformNode(Node *pNode)
00848 
00849     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00850     Created:    09/08/96
00851     Inputs:     pointer to node to fiddle with
00852     Returns:    error flag
00853     Purpose:    transforms the node to the correct place on the page. Only give it
00854                 nodes which are kinds of NodeRenderableBounded.
00855 
00856 ********************************************************************************************/
00857 
00858 BOOL CMXImportFilter::TransformNode(Node *pNode)
00859 {
00860     ERROR2IF(Data->pCurrentMatrix == NULL, FALSE, "No matrix to transform by");
00861 
00862     // transform the node
00863     Trans2DMatrix Transform(*Data->pCurrentMatrix);
00864     NodeRenderableBounded *pBN = (NodeRenderableBounded *)pNode;
00865     ERROR3IF(!pBN->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableBounded)), "not a transformable node passed to TransformNode");
00866     pBN->Transform(Transform);
00867 
00868     // do some funky stuff on it
00869     DocRect BBox = pBN->GetBoundingRect(TRUE, FALSE);
00870     if(Data->HaveFirstObjInBoundsRect == FALSE)
00871     {
00872         // set the bbox
00873         Data->HaveFirstObjInBoundsRect = TRUE;
00874         Data->AllObjectsBoundsRect = BBox;
00875     }
00876     else
00877     {
00878         Data->AllObjectsBoundsRect = Data->AllObjectsBoundsRect.Union(BBox);
00879     }
00880 
00881 
00882     return TRUE;
00883 }
00884 
00885 
00886 /********************************************************************************************
00887 
00888 >   BOOL CMXImportFiler::SetAttributesForNode(Node *pNode, cmxiRenderAttr *pAttr)
00889 
00890     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
00891     Created:    09/08/96
00892     Inputs:     pointer to node to fiddle with, pointer to attributes from CMX file
00893     Returns:    error flag
00894     Purpose:    sets the attributes for the node. The bits and pieces from the
00895                 render attributes thingy are deleted, so you can't use them twice
00896 
00897 ********************************************************************************************/
00898 
00899 #define MAXLINEWIDTH    (720000 * 2)        // sounds reasonable
00900 
00901 BOOL CMXImportFilter::SetAttributesForNode(Node *pNode, void *pvAttr, BOOL DeleteStuff)
00902 {
00903     cmxiRenderAttr *pAttr = (cmxiRenderAttr *)pvAttr;
00904 
00905     // remove lens attributes?
00906     if(Data->RemoveLens)
00907     {
00908         Data->RemoveLens = FALSE;
00909         if(!SetNoTranspFill())
00910             return FALSE;
00911     }
00912 
00913     BOOL DoFillStuff = TRUE;
00914 
00915     // -----------------------------------------  fills
00916     if((pAttr->Mask & cmxRENDATTRMASK_LENS) != 0)
00917     {
00918         // can we handle the lens?
00919         if(pAttr->LensSpec.Type == cmxLENSTYPE_GLASS)
00920         {
00921             UINT32 Type;
00922 
00923             // yep, it's one of those glass ones
00924             switch(pAttr->LensSpec.Glass.TintMethod)
00925             {
00926             case cmxLENSTINTMETH_SUBTRACT:
00927                 Type = TT_StainGlass;
00928                 break;
00929 
00930             case cmxLENSTINTMETH_ADD:
00931                 Type = TT_Bleach;
00932                 break;
00933 
00934             case cmxLENSTINTMETH_AVERAGE:
00935                 Type = TT_Mix;
00936                 break;
00937 
00938             default:
00939                 Type = TT_Mix;
00940                 AttributeApproximated();
00941                 break;
00942             }
00943 
00944             // munge to our range
00945             UINT32 Percent = 255 - ((pAttr->LensSpec.Glass.UniformRate * 255) / 1000);
00946 
00947             // set the attribute
00948             if(!SetFlatTranspFill(Type, Percent))
00949                 return FALSE;
00950 
00951             // set the colour of the object
00952             DocColour *pColour = GetColourFromReference(pAttr->LensSpec.Glass.ColourRef);
00953             if(pColour == NULL)
00954                 return FALSE;
00955             // set the attribute
00956             if(!SetFillColour(*pColour))
00957                 return FALSE;
00958 
00959             Data->RemoveLens = TRUE;    // something to remove next time around
00960             DoFillStuff = FALSE;        // we've handled all fill type stuff
00961         }
00962         else
00963         {
00964             AttributeApproximated();    // mark the fact we've ignored something
00965         }
00966     }
00967 
00968     // -----------------------------------------  fills
00969     if(DoFillStuff)
00970     {
00971         if((pAttr->Mask & cmxRENDATTRMASK_FILL) != 0)
00972         {
00973             // got a fill -- set filledness
00974             Data->ObjFilled = TRUE;
00975             SetPathFilled(TRUE);
00976 
00977             // set attributes for it
00978             BOOL UnknownFill = FALSE;
00979 
00980             TRACEUSER( "Ben", _T("   fill type is %d\n"), pAttr->FillSpec.FillID);
00981             // here we convert the stuff, and delete anything which is created
00982             // for us
00983             switch(pAttr->FillSpec.FillID)
00984             {
00985             case cmxFILLID_UNIFORM:
00986                 {
00987                     // get a colour for the fill
00988                     DocColour *pColour = GetColourFromReference(pAttr->FillSpec.Spec.Uniform.ColourReference);
00989                     if(pColour == NULL)
00990                         return FALSE;
00991                     // set the attribute
00992                     if(!SetFillColour(*pColour))
00993                         return FALSE;
00994                 }
00995                 break;
00996 
00997             case cmxFILLID_FOUNTAIN:
00998                 if(!SetAttributesFountain(pNode, &pAttr->FillSpec))
00999                 {
01000                     if(DeleteStuff) delete pAttr->FillSpec.Spec.Fountain.pColours;
01001                     return FALSE;
01002                 }
01003 
01004                 if(DeleteStuff) delete pAttr->FillSpec.Spec.Fountain.pColours;
01005                 break;
01006 
01007             case cmxFILLID_PS:
01008                 if(DeleteStuff) delete pAttr->FillSpec.Spec.Postscript.UserFunction;
01009                 break;
01010 
01011             case cmxFILLID_COLPATTERN:
01012                 if(!SetAttributesTwoColourBitmapFill(pNode, &pAttr->FillSpec))
01013                     return FALSE;
01014                 break;
01015 
01016             case cmxFILLID_BITMAPFILL:
01017             case cmxFILLID_BITMAPFILL16:    // also vector fills in v6
01018                 // we've got one of those possible bitmap fill type things
01019                 if(!SetAttributesBitmapFill(pNode, pAttr->FillSpec.Spec.Bitmap.VectorFillReference, &pAttr->FillSpec.Spec.Bitmap.Tile))
01020                     return FALSE;
01021                 break;
01022 
01023             case cmxFILLID_TEXTURE:
01024                 if(!SetAttributesBitmapFill(pNode, pAttr->FillSpec.Spec.Texture.VectorFillReference, &pAttr->FillSpec.Spec.Texture.Tile))
01025                     return FALSE;
01026                 break;
01027 
01028             default:
01029                 // dunno nothing about this kind of fill ID -- set to no colour
01030                 UnknownFill = TRUE;
01031                 break;
01032             }
01033 
01034             if(UnknownFill)
01035             {
01036                 // give a fill no colour if we don't know how to do it
01037                 AttributeApproximated();
01038                 if(!SetNoFill(pNode))
01039                     return FALSE;
01040             }
01041         }
01042         else
01043         {
01044             Data->ObjFilled = FALSE;
01045 
01046             // no fill here
01047             if(!SetNoFill(pNode))
01048                 return FALSE;
01049         }
01050     }
01051 
01052     // -----------------------------------------  outline
01053     if((pAttr->Mask & cmxRENDATTRMASK_OUTLINE) != 0)
01054     {
01055         // right then, get the outline defn
01056         CMXImportOutline *pOut;
01057         if(pAttr->OutlineReference <= 0 || pAttr->OutlineReference > Data->NumOutlines)
01058             CMXFORMATERROR(FALSE)       // outline ref out of range
01059 
01060         pOut = &Data->Outlines[pAttr->OutlineReference - 1];
01061 
01062         if(pOut->NoStroke)
01063         {
01064             if(!SetNoStroke(pNode))
01065                 return FALSE;
01066         }
01067         else
01068         {
01069             // have an outline to fiddle with...
01070 
01071             // get the colour
01072             DocColour *pCol = GetColourFromReference(pOut->ColourReference);
01073             if(pCol == NULL)
01074                 return FALSE;
01075 
01076             // set it...
01077             if(!SetLineColour(*pCol))
01078                 return FALSE;
01079 
01080             // do the line width
01081             double LineWidth = pOut->Width * Data->BaseScaleFactor;
01082             if(LineWidth > MAXLINEWIDTH) LineWidth = MAXLINEWIDTH;
01083             if(!SetLineWidth((MILLIPOINT)LineWidth))
01084                 return FALSE;
01085 
01086             // do that funky dot dash pattern thingy
01087             DashRec Dash;
01088             if(pOut->pDots != NULL && pOut->pDots->NDots != 0)
01089             {
01090                 // set a dash pattern
01091                 Dash.Elements = pOut->pDots->NDots;
01092                 Dash.DashStart = 0;
01093                 Dash.ElementData = pOut->pDots->pElements;
01094                 Dash.LineWidth = 1; //(MILLIPOINT)LineWidth;
01095                 Dash.ScaleWithLineWidth = TRUE;
01096                 Dash.DashID = -1;
01097             }
01098             else
01099             {
01100                 // no dash pattern
01101                 Dash = SD_SOLID;
01102             }
01103 
01104             // do the cap and join bits
01105             if(!SetLineCap(pOut->Cap)
01106                 || !SetJoinType(pOut->Join)
01107                 || !SetDashPattern(Dash))
01108                 return FALSE;
01109 
01110             // do arrowheads
01111             if(pOut->pArrowheads != NULL)
01112             {
01113                 // got some arrowheads...
01114                 // -- <> -- START
01115                 if(pOut->pArrowheads->pStart != NULL)
01116                 {
01117                     if(!SetStartArrow(pOut->pArrowheads->pStart->Arrow))
01118                         return FALSE;
01119                 }
01120                 else
01121                 {
01122                     ArrowRec NullArrow;
01123                     if(!SetStartArrow(NullArrow))
01124                         return FALSE;
01125                 }
01126 
01127                 // -- <> -- END
01128                 if(pOut->pArrowheads->pEnd != NULL)
01129                 {
01130                     if(!SetEndArrow(pOut->pArrowheads->pEnd->Arrow))
01131                         return FALSE;
01132                 }
01133                 else
01134                 {
01135                     ArrowRec NullArrow;
01136                     if(!SetEndArrow(NullArrow))
01137                         return FALSE;
01138                 }
01139             }
01140             else
01141             {
01142                 // no arrowheads -- set a null arrow rec
01143                 ArrowRec NullArrow;
01144                 if(!SetStartArrow(NullArrow)
01145                     || !SetEndArrow(NullArrow))
01146                     return FALSE;
01147             }
01148         }
01149     }
01150     else
01151     {
01152         if(!SetNoStroke(pNode))
01153             return FALSE;
01154     }
01155 
01156     return TRUE;
01157 }
01158 
01159 
01160 /********************************************************************************************
01161 
01162 >   BOOL CMXImportFilter::SetNoFill(Node *pNode)
01163 
01164     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01165     Created:    13/08/96
01166     Inputs:     node
01167     Returns:    error flag
01168     Purpose:    sets attributes for this node to have no fill -- also fiddles it if it's
01169                 a path
01170 
01171 ********************************************************************************************/
01172 
01173 BOOL CMXImportFilter::SetNoFill(Node *pNode)
01174 {
01175     if(pNode->IsKindOf(CC_RUNTIME_CLASS(NodePath)))
01176     {
01177         NodePath *pPath = (NodePath *)pNode;
01178 
01179 //      pPath->InkPath.IsFilled = FALSE;
01180     }
01181 
01182     Data->ObjFilled = FALSE;
01183 
01184     SetFillColour(DocColour(COLOUR_TRANS));
01185 
01186     return SetPathFilled(FALSE);
01187 }
01188 
01189 
01190 /********************************************************************************************
01191 
01192 >   BOOL CMXImportFilter::SetNoStroke(Node *pNode)
01193 
01194     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01195     Created:    13/08/96
01196     Inputs:     node
01197     Returns:    error flag
01198     Purpose:    sets attributes for this node to have no stroke colour -- also fiddles
01199                 it if it's a path
01200 
01201 ********************************************************************************************/
01202 
01203 BOOL CMXImportFilter::SetNoStroke(Node *pNode)
01204 {
01205 
01206 // Jim 13/9/96 - Setting Transparent stroke colour is enough - don't set IsStroked to FALSE
01207 // otherwise it stops them rendering at zero quality.
01208 //  if(pNode->IsKindOf(CC_RUNTIME_CLASS(NodePath)))
01209 //  {
01210 //      NodePath *pPath = (NodePath *)pNode;
01211 //
01212 //      pPath->InkPath.IsStroked = FALSE;
01213 //  }
01214 
01215     SetLineColour(DocColour(COLOUR_TRANS));
01216 
01217     return TRUE;
01218 }
01219 
01220 
01221 class CMXBecomeA : public BecomeA
01222 {
01223 public:
01224     CMXBecomeA(BecomeAReason ThisReason, CCRuntimeClass* pClass, UndoableOperation* pOp, BOOL sel=TRUE)
01225         : BecomeA(ThisReason, pClass, pOp, sel) {};
01226 
01227     BOOL PassBack(NodeRenderableInk* pNewNode,NodeRenderableInk* pCreatedByNode,CCAttrMap* pAttrMap=NULL);
01228 
01229     NodePath *pPath;
01230 };
01231 
01232 /********************************************************************************************
01233 
01234 >   BOOL CMXBecomeA::PassBack(NodeRenderableInk* pNewNode,NodeRenderableInk* pCreatedByNode,CCAttrMap* pAttrMap=NULL)
01235 
01236     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01237     Created:    25/08/96
01238     Inputs:     random stuff
01239     Returns:    error flag
01240     Purpose:    stores the pointer to the copy of my thingy, and bungs the attributes
01241                 on it.
01242 
01243 ********************************************************************************************/
01244 
01245 BOOL CMXBecomeA::PassBack(NodeRenderableInk* pNewNode,NodeRenderableInk* pCreatedByNode,CCAttrMap* pAttrMap)
01246 {
01247     pPath = (NodePath *)pNewNode;
01248 
01249     if(pAttrMap != NULL)
01250     {
01251         // iterating all (key, value) pairs
01252         for (POSITION Pos = pAttrMap->GetStartPosition(); Pos != NULL;)
01253         {
01254             void *pType,*pVal;
01255             pAttrMap->GetNextAssoc(Pos,pType,pVal);
01256 
01257             // Get the attribute value of this attribute
01258             NodeAttribute* pAttr = (NodeAttribute*)pVal;
01259 
01260             // bung the attribute onto the node thingy
01261             pAttr->AttachNode(pNewNode, LASTCHILD);
01262         }
01263     }
01264 
01265     return TRUE;
01266 }
01267 
01268 /********************************************************************************************
01269 
01270 >   BOOL CMXImportFiler::ClipNode(Node **pNode)
01271 
01272     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01273     Created:    09/08/96
01274     Inputs:     pointer to pointer to node to clip
01275     Returns:    error flag
01276     Purpose:    clips the node to the current clipping path. Note that it may delete this
01277                 one and change your pointer to a completely new node, just for the fun
01278                 of it.
01279 
01280 ********************************************************************************************/
01281 
01282 BOOL CMXImportFilter::ClipNode(Node **pNode)
01283 {
01284     if(Data->pClippingPath == NULL)
01285         return TRUE;        // nothin' to do
01286 
01287     NodePath *pPath = NULL;
01288 
01289     // check to see what kind of node we've got
01290     if(!IS_A(*pNode, NodePath))
01291     {
01292         CMXBecomeA ParamBecomeA(BECOMEA_PASSBACK, 
01293                              CC_RUNTIME_CLASS(NodePath),
01294                              NULL, FALSE);
01295 
01296         if((*pNode)->IsKindOf(CC_RUNTIME_CLASS(NodeRenderableInk)))
01297         {
01298             if ((*pNode)->CanBecomeA(&ParamBecomeA))
01299             {
01300                 // is it a text story?
01301                 if((*pNode)->IsKindOf(CC_RUNTIME_CLASS(TextStory)))
01302                 {
01303                     // give formatting it a go
01304                     ((TextStory *)*pNode)->FormatAndChildren();
01305                 }
01306                 
01307                 if (!(*pNode)->DoBecomeA(&ParamBecomeA))
01308                 {
01309                     return FALSE;
01310                 }
01311 
01312                 // quick check...
01313                 if(!IS_A(ParamBecomeA.pPath, NodePath))
01314                 {
01315                     // didn't get a path!
01316                     delete ParamBecomeA.pPath;
01317                     return TRUE;        // don't complain, I suppose
01318                 }
01319 
01320                 // right then, replace the node with this one
01321                 (*pNode)->CascadeDelete();
01322                 delete *pNode;
01323                 *pNode = ParamBecomeA.pPath;
01324                 pPath = ParamBecomeA.pPath;
01325             }
01326         }
01327     }
01328     else
01329     {
01330         pPath = (NodePath *)*pNode;
01331     }
01332     ERROR2IF(pPath == NULL, FALSE, "no path, even though we tried really really hard");
01333 
01334     // right then, we've got to do something fabby. Get a new path to stuff stuff in
01335     Path *pOutputPath = new Path;
01336     if(pOutputPath == NULL || !pOutputPath->Initialise())
01337         return FALSE;       // something went wrong
01338 
01339     // clip the thingy to the thingy
01340     if(Data->pClippingPath->ClipPathToPath(pPath->InkPath, pOutputPath, 2 /*CLIP_STYLE_INTERSECT*/) > 0)
01341     {
01342         // clipping produced something...
01343         // now replace the path with the output path
01344         if(!pPath->InkPath.CloneFrom(*pOutputPath))
01345             return FALSE;
01346     }
01347     else
01348     {
01349         // clipping didn't produce anything -- delete the thingy
01350         pPath->CascadeDelete();
01351         delete pPath;
01352 
01353         // nothing doing, chaps.
01354         (*pNode) = NULL;
01355     }
01356 
01357     // delete the output path, don't need it any more
01358     delete pOutputPath;
01359 
01360     return TRUE;
01361 }
01362 
01363 
01364 /********************************************************************************************
01365 
01366 >   BOOL CMXImportFilter::GetCorelBBox(NodeRenderable *pNode, DocRect *BBox)
01367 
01368     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01369     Created:    15/08/96
01370     Inputs:     node and a pointer to bbox to fill in
01371     Returns:    error flag
01372     Purpose:    gets the Corel simple union bbox of an object
01373 
01374 ********************************************************************************************/
01375 
01376 BOOL CMXImportFilter::GetCorelBBox(NodeRenderableBounded *pNode, DocRect *BBox)
01377 {
01378     if(pNode->IsKindOf(CC_RUNTIME_CLASS(NodePath)))
01379     {
01380         // ok, so it's a path. That means we can run through it to find out the simple
01381         // union of all points. 
01382 
01383         NodePath *pNodePath = (NodePath *)pNode;
01384 
01385         // get a pointer to the array of coords in the nice path
01386         INT32 NCoords = pNodePath->InkPath.GetNumCoords();
01387         DocCoord *Coords = pNodePath->InkPath.GetCoordArray();
01388 
01389         ERROR3IF(NCoords < 1, "Awooga! Trying to find a corel bbox of a path with less than one coord.");
01390 
01391         INT32 c;
01392 
01393         INT32 x0, y0, x1, y1;
01394 
01395         // initialise my bbox variables
01396         x0 = x1 = Coords[0].x;
01397         y0 = y1 = Coords[0].y;
01398         
01399         for(c = 1; c < NCoords; c++)
01400         {
01401             // update my bbox
01402             if(Coords[c].x < x0) x0 = Coords[c].x;
01403             if(Coords[c].y < y0) y0 = Coords[c].y;
01404             if(Coords[c].x > x1) x1 = Coords[c].x;
01405             if(Coords[c].y > y1) y1 = Coords[c].y;
01406         }
01407 
01408         // fill in *BBox
01409         BBox->lo.x = x0;
01410         BBox->lo.y = y0;
01411         BBox->hi.x = x1;
01412         BBox->hi.y = y1;
01413     } else {
01414         // if it's not a path object, ask the node what it's bounding box is - we'll just
01415         // have to make do with a *correct* bounding box instead of simply corel union.
01416         *BBox = pNode->GetBoundingRect();
01417     }
01418 
01419     return TRUE;
01420 }
01421 
01422 
01423 /********************************************************************************************
01424 
01425 >   BOOL CMXImportFiler::ApplyAttributesToNode(Node *pNode)
01426 
01427     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01428     Created:    09/08/96
01429     Inputs:     pointer to node to fiddle with, pointer to attributes from CMX file
01430     Returns:    error flag
01431     Purpose:    adds the attributes to the node.
01432 
01433 ********************************************************************************************/
01434 
01435 BOOL CMXImportFilter::ApplyAttributesToNode(Node *pNode)
01436 {
01437     // not having a node is a valid option here, and shouldn't be complained at
01438     // as the previous clipping operation may have decided that there wasn't anything
01439     // there after the intersection
01440     if(pNode == NULL)
01441         return TRUE;
01442 
01443     // apply the attributes to the object
01444     // If not filled, then set the ignore bit on the fill attribute.
01445     if(Data->ObjFilled == FALSE)
01446         CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = TRUE;
01447 
01448     // Add attributes to the path, if they are different from the default...
01449     BOOL Result = AttributeManager::ApplyBasedOnDefaults(pNode, CurrentAttrs);
01450 
01451     // Enable the fill attribute again
01452     CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = FALSE;
01453 
01454     return Result;
01455 }
01456 
01457 
01458 /********************************************************************************************
01459 
01460 >   BOOL CMXImportFilter::GotoSectionFromIndex(INT32 MasterIndexEntry, DWORD PredictedRIFFType,
01461             BOOL NonExistanceIsFormatError)
01462 
01463     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01464     Created:    13/08/96
01465     Inputs:     MasterIndexEntry - entry to read position from
01466                 PredictedRIFFType - the type the RIFF section should have
01467                 NonExistanceIsFormatError - whether it's a format error for the section
01468                         not to exist
01469                 Found - pointer to flag to say whether we got it or not (can be null)
01470     Returns:    error flag
01471     Purpose:    positions the file pointer after the riff header for a section defined
01472                 in the master index
01473 
01474 ********************************************************************************************/
01475 
01476 BOOL CMXImportFilter::GotoSectionFromIndex(INT32 MasterIndexEntry, DWORD PredictedRIFFType,
01477         BOOL NonExistanceIsFormatError, BOOL *Found, INT32 *Size)
01478 {
01479     if(Found != 0)
01480         (*Found) = FALSE;
01481 
01482     if(Data->MasterIndexEntries[MasterIndexEntry] == 0)
01483     {
01484         // if non-existance is a problem, do an error
01485         if(NonExistanceIsFormatError)
01486             CMXFORMATERROR(FALSE)
01487     
01488         // otherwise return true, but the found flag marks the problem
01489         return TRUE;
01490     }
01491 
01492     if(Found != 0)
01493         (*Found) = TRUE;
01494 
01495     TRACEUSER( "Ben", _T("index entry %d at %d\n"), MasterIndexEntry, Data->MasterIndexEntries[MasterIndexEntry]);
01496     Seek(Data->MasterIndexEntries[MasterIndexEntry]);
01497     RIFFck chdr;
01498     pFile->read(&chdr, sizeof(chdr));
01499     if(chdr.ckID != PredictedRIFFType)
01500         CMXFORMATERROR(FALSE)
01501 
01502     if(Size != 0)
01503         (*Size) = chdr.ckSize;
01504 
01505     return TRUE;
01506 }
01507 
01508 
01509 
01510 
01511 /********************************************************************************************
01512 
01513 >   BOOL CMXImportFilter::SetAttributesFountain(Node *pNode, cmxiFillSpec *Fill)
01514 
01515     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01516     Created:    15/08/96
01517     Inputs:     pointer to fill header
01518     Returns:    error flag
01519     Purpose:    sets graduated fill attributes
01520 
01521 ********************************************************************************************/
01522 
01523 BOOL CMXImportFilter::SetAttributesFountain(Node *pNode, cmxiFillSpec *Fill)
01524 {
01525     // find the bounding box of this lovely node
01526     DocRect BBox;
01527     if(!GetCorelBBox((NodeRenderableBounded *)pNode, &BBox))
01528         return FALSE;
01529 
01530     // find the minimum and maximim percentages along the grad fill line.
01531     DocColour *pStartColour = GetColourFromReference(Fill->Spec.Fountain.pColours->GetColourRefClosestToPosition(0));
01532     DocColour *pEndColour = GetColourFromReference(Fill->Spec.Fountain.pColours->GetColourRefClosestToPosition(100));
01533 
01534     // if it's a rainbow effect, work out whether an anti-clockwise thingy will be a
01535     // a normal or alt rainbow fill
01536     BOOL NormalRainbow = TRUE;
01537     if(Fill->Spec.Fountain.FillMode == cmxFILLMODE_HSB_CW ||
01538              Fill->Spec.Fountain.FillMode == cmxFILLMODE_HSB_CCW)
01539     {
01540         // convert both colours to HSV to find their hue
01541         ColourContext *Conv = ColourContext::GetGlobalDefault(COLOURMODEL_HSVT);
01542 
01543         ColourHSVT StartC;
01544         ColourHSVT EndC;
01545 
01546         Conv->ConvertColour(pStartColour, (ColourGeneric *)&StartC);
01547         Conv->ConvertColour(pEndColour, (ColourGeneric *)&EndC);
01548 
01549         // compare the hues and work out a difference
01550         ColourValue Difference;
01551 
01552         if(EndC.Hue > StartC.Hue)
01553         {
01554             Difference = EndC.Hue - StartC.Hue;
01555         } else {
01556             Difference = 1.0 - (StartC.Hue - EndC.Hue);
01557         }
01558 
01559         // if the difference is more than 0.5 then it's a alt rainbow thingy
01560         if(Difference > fixed24(0.5))
01561             NormalRainbow = FALSE;
01562     }
01563 
01564     // set the fade effect
01565     switch(Fill->Spec.Fountain.FillMode)
01566     {
01567         case cmxFILLMODE_RGB:
01568         case cmxFILLMODE_CUSTOM:
01569         default:
01570             SetFadeFillEffect();
01571             break;
01572 
01573         case cmxFILLMODE_HSB_CCW:
01574             if(NormalRainbow)
01575                 SetRainbowFillEffect();
01576             else
01577                 SetAltRainbowFillEffect();
01578             break;
01579 
01580         case cmxFILLMODE_HSB_CW:
01581             if(NormalRainbow)
01582                 SetAltRainbowFillEffect();
01583             else
01584                 SetRainbowFillEffect();
01585             break;
01586     }
01587 
01588     // and finally, sort out the start and end points of the thingy
01589     switch(Fill->Spec.Fountain.Type)
01590     {
01591         case cmxFOUNTAINTYPE_LINEAR:
01592             if(!SetAttributesLinearGrad(pNode, Fill, BBox, pStartColour, pEndColour))
01593                 return FALSE;
01594             break;
01595 
01596         case cmxFOUNTAINTYPE_RADIAL:
01597             if(!SetAttributesRadialGrad(pNode, Fill, BBox, pStartColour, pEndColour))
01598                 return FALSE;
01599             break;
01600 
01601         case cmxFOUNTAINTYPE_SQUARE:
01602             if(!SetAttributesRadialGrad(pNode, Fill, BBox, pStartColour, pEndColour, TRUE))
01603                 return FALSE;
01604             break;
01605 
01606         case cmxFOUNTAINTYPE_CONICAL:
01607             if(!SetAttributesConicalGrad(pNode, Fill, BBox, pStartColour, pEndColour))
01608                 return FALSE;
01609             break;
01610 
01611         default:            
01612             return SetNoFill(pNode);
01613             break;
01614     }
01615 
01616     return TRUE;
01617 }
01618 
01619 
01620 /********************************************************************************************
01621 
01622 >   BOOL CMXImportFilter::SetAttributesLinearGrad(Node *pNode, cmxiFillSpec *GFill, DocRect &BBox, DocColour *StartColour, DocColour *EndColour)
01623 
01624     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01625     Created:    15/08/96
01626     Inputs:     grad fill defn and converted colours for the fill
01627     Returns:    error flag
01628     Purpose:    sets a linear graduated fill from fill definition in the file
01629                 Copied from coreleps.cpp and modified
01630     SeeAlso:    Filter
01631 
01632 ********************************************************************************************/
01633 
01634 BOOL CMXImportFilter::SetAttributesLinearGrad(Node *pNode, cmxiFillSpec *GFill, DocRect &BBox, DocColour *StartColour, DocColour *EndColour)
01635 {
01636     // NB. this function is (hopefully!) over-complex and will be simplified.
01637     // However, it's like this atm so I can get my head around the weird maths Corel 
01638     // forces us to use.
01639 
01640     // The desired start and end points of the grad fill 'arrow'.
01641     DocCoord Start, End;
01642 
01643     // Calculate width and height
01644     MILLIPOINT Width = BBox.Width();
01645     MILLIPOINT Height = BBox.Height();
01646 
01647     // bodge just in case of zero height or widths
01648     if(Width < 16)
01649         Width = 16;
01650 
01651     if(Height < 16)
01652         Height = 16;
01653 
01654     // Find centre of box
01655     DocCoord Centre;
01656     Centre.x = BBox.lo.x + (Width / 2);
01657     Centre.y = BBox.lo.y + (Height / 2);
01658 
01659     // Find total area of BBox
01660     double TotalArea = (double) Width * (double) Height;
01661 
01662     // Cope with angles > 180
01663     BOOL Mirror = FALSE;
01664     double Angle = GFill->Spec.Fountain.Angle;
01665     
01666     if (Angle >= PI)
01667     {
01668         Angle -= PI;
01669         Mirror = TRUE;
01670     }
01671     else if (Angle < 0)
01672     {
01673         Angle += PI;
01674         Mirror = TRUE;
01675     }
01676 
01677     Angle += (PI/2);
01678 
01679     if (Angle >= PI)
01680     {
01681         Angle -= PI;
01682     }
01683 
01684     // get edge pad value
01685     INT32 EdgePad = GFill->Spec.Fountain.Padding;
01686     
01687     // Calculate tan of the angle - convert angle to radians first.
01688     double TanTheta;
01689     if (Angle == (PI/2))
01690     {
01691         // Special case for horizontal grad fill arrow.
01692 
01693         // Make 0% padding first
01694         Start.x = BBox.lo.x;
01695         Start.y = Centre.y;
01696         End.x = BBox.hi.x;
01697         End.y = Centre.y;
01698 
01699         // Find out width of padding
01700         INT32 Padding = (Width * EdgePad) / 100;
01701         Start.x += Padding;
01702         End.x -= Padding;
01703     }
01704     else if (Angle == 0)
01705     {
01706         // Special case for vertical grad fill arrow.
01707 
01708         // Make 0% padding first
01709         Start.x = Centre.x;
01710         Start.y = BBox.lo.y;
01711         End.x = Centre.x;
01712         End.y = BBox.hi.y;
01713 
01714         // Find out width of padding
01715         INT32 Padding = (Height * EdgePad) / 100;
01716         Start.y += Padding;
01717         End.y -= Padding;
01718     }
01719     else
01720     {
01721         TanTheta = tan(Angle);
01722 
01723         // Find out what the maximum padding is that we can achieve using just triangles:
01724 
01725         // Find the maximum triangle width
01726         MILLIPOINT TriWidth = (MILLIPOINT) ((double) Height / TanTheta);
01727 
01728         // Limit it to sensible value
01729         if (TriWidth < 0)
01730             TriWidth = -TriWidth;
01731         if (TriWidth > Width)
01732             TriWidth = Width;
01733 
01734         // Find the maximum triangle width
01735         MILLIPOINT TriHeight = (MILLIPOINT) ((double) Width * TanTheta);
01736 
01737         // Limit it to sensible value
01738         if (TriHeight < 0)
01739             TriHeight = -TriHeight;
01740         if (TriHeight > Height)
01741             TriHeight = Height;
01742 
01743         // The 'c' values of the y = mx+c equation.
01744         MILLIPOINT StartC, EndC;
01745 
01746         // Work out the maximum percentage/edge padding this gives us
01747         // (50 because it's 100 / 2 because we want area of triangle, not rectangle).
01748         double Percentage = (50.0 * (double) TriWidth * (double) TriHeight) / TotalArea;
01749 
01750         INT32 Diff = 0;
01751 
01752         // Is this enough?
01753         if (((INT32) Percentage) >= EdgePad)
01754         {
01755             // Yes - calculate exactly how big the triangle needs to be.
01756             TriHeight = (MILLIPOINT) sqrt(ABS(((double) EdgePad * TotalArea * TanTheta) / 100.0));
01757 
01758             TriWidth = (MILLIPOINT) ((double) TriHeight / TanTheta);
01759             if (TriWidth < 0)
01760                 TriWidth = -TriWidth;
01761 
01762             ENSURE(TriWidth < Width, "Error in Corel Grad fill decoding logic");
01763         }
01764         else
01765         {
01766             // How much percentage do we need to add with each rectangle?
01767             Percentage = (EdgePad - Percentage) / 2;
01768 
01769             // Handle the rectangle stuff.
01770             if (TriWidth == Width)
01771             {
01772                 // Need to add rectangles to the top and bottom.
01773                 Diff = (MILLIPOINT) ((Percentage * Height) / 100.0);
01774             }
01775             else
01776             {
01777                 // Need to add rectangles to left and right
01778                 Diff = (MILLIPOINT) ((Percentage * Width) / 100.0);
01779                 Diff = (MILLIPOINT) (Diff / tan(PI - Angle));
01780                 Diff = ABS(Diff);
01781             }
01782         }
01783 
01784         // Work out the C value for the start line (c = y - mx)
01785         // (m = tan(angle) )
01786         if (Angle == (PI/2))
01787         {
01788             //ENSURE(FALSE, "90 degree angle found!");
01789         }
01790         else if (Angle < (PI/2))
01791         {
01792             StartC = (MILLIPOINT) (BBox.lo.y - ((BBox.hi.x - TriWidth) * TanTheta));
01793             EndC = (MILLIPOINT) (BBox.hi.y - ((BBox.lo.x + TriWidth) * TanTheta));
01794         }
01795         else
01796         {
01797             StartC = (MILLIPOINT) (BBox.lo.y - ((BBox.lo.x + TriWidth) * TanTheta));
01798             EndC = (MILLIPOINT) (BBox.hi.y - ((BBox.hi.x - TriWidth) * TanTheta));
01799         }
01800 
01801         // Add on difference for rectangles, if any.
01802         StartC += Diff;
01803         EndC -= Diff;
01804 
01805 
01806         // Work out m and c for the grad fill line.
01807         // We know m is -1/m of the triangle's hypotenuse.
01808         // c = roy - (rox/m)
01809         double FillM = -1.00 / TanTheta;
01810         MILLIPOINT FillC = (MILLIPOINT) (Centre.y - (Centre.x * FillM));
01811 
01812         // Work out intersections:  x = (c2 - c1) / (2m)
01813 
01814         Start.x = (MILLIPOINT) ( (FillC - StartC) / (TanTheta + (1.00 / TanTheta)) );
01815         Start.y = (MILLIPOINT) ((FillM * Start.x) + FillC);
01816 
01817         End.x = (MILLIPOINT) ( (FillC - EndC) / (TanTheta + (1.00 / TanTheta)) );
01818         End.y = (MILLIPOINT) ((FillM * End.x) + FillC);
01819     }
01820 
01821     if (Mirror)
01822     {
01823         // Swap the grid fill end-points over.
01824         DocCoord Tmp = Start;
01825         Start = End;
01826         End = Tmp;
01827     }
01828 
01829     // Set the fill type according to these calculations.
01830     return SetLinearFill(*StartColour, *EndColour, Start, End); 
01831 }
01832 
01833 
01834 /********************************************************************************************
01835 
01836 >   BOOL CMXImportFilter::SetAttributesConicalGrad(Node *pNode, cmxiFillSpec *GFill, DocRect &BBox, DocColour *StartColour, DocColour *EndColour)
01837 
01838     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01839     Created:    15/08/96
01840     Inputs:     grad fill defn and converted colours for the fill
01841     Returns:    error flag
01842     Purpose:    sets a conical graduated fill from fill definition in the file
01843 
01844 ********************************************************************************************/
01845 
01846 BOOL CMXImportFilter::SetAttributesConicalGrad(Node *pNode, cmxiFillSpec *GFill, DocRect &BBox, DocColour *StartColour, DocColour *EndColour)
01847 {
01848     // The desired start and end points of the grad fill 'arrow'.
01849     DocCoord Start, End;
01850 
01851     // Calculate width and height
01852     MILLIPOINT Width = BBox.Width();
01853     MILLIPOINT Height = BBox.Height();
01854 
01855     // Start point is the centre given by Corel.
01856     // This centre is percentage offsets from the centre of the object, i.e. (0,0) is
01857     // the centre of the bounding box.
01858     Start.x = BBox.lo.x + (Width  / 2);
01859     Start.y = BBox.lo.y + (Height / 2);
01860     Start.x += ((GFill->Spec.Fountain.Offset.x * Width) / 100);
01861     Start.y += ((GFill->Spec.Fountain.Offset.y * Height) / 100);
01862 
01863     // End point is start point + radius but takes into account the angle
01864     double Radius = Width / 2;
01865     double Theta = GFill->Spec.Fountain.Angle;
01866     
01867     // make the angle go anti-clockwise
01868     Theta = 0 - Theta;
01869 
01870     // rotate by PI / 2
01871     Theta -= PI / 2;
01872     
01873     // angle can be negative, ensure it's positive
01874     while(Theta < 0)
01875         Theta += (2 * PI);
01876 
01877     // calculate the triangle
01878     double dx, dy;
01879 
01880     dx = Radius * sin(Theta);
01881     dy = Radius * cos(Theta);
01882 
01883     End.x = Start.x + (INT32)dx;
01884     End.y = Start.y + (INT32)dy;
01885 
01886     // Seems that we need to swap start and end colours...
01887 
01888     // Set the fill type according to these calculations.
01889     return SetConicalFill(*EndColour, *StartColour, Start, End);    
01890 }
01891 
01892 
01893 /********************************************************************************************
01894 
01895 >   BOOL CMXImportFilter::SetAttributesRadialGrad(Node *pNode, cmxiFillSpec *GFill, DocRect &BBox, DocColour *StartColour, DocColour *EndColour)
01896 
01897     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01898     Created:    15/08/96
01899     Inputs:     grad fill defn and converted colours for the fill
01900     Returns:    error flag
01901     Purpose:    sets a radial graduated fill from fill definition in the file
01902 
01903 ********************************************************************************************/
01904 
01905 BOOL CMXImportFilter::SetAttributesRadialGrad(Node *pNode, cmxiFillSpec *GFill, DocRect &BBox, DocColour *StartColour, DocColour *EndColour, BOOL IsSquare)
01906 {
01907     // The desired start and end points of the grad fill 'arrow'.
01908     DocCoord Start, End, End2;
01909 
01910     // Calculate width and height
01911     MILLIPOINT Width = BBox.Width();
01912     MILLIPOINT Height = BBox.Height();
01913 
01914     // caluculate the source area
01915     // first, what's the diagonal length
01916     double dWidth = Width;
01917     double dHeight = Height;
01918     INT32 Diagonal = (INT32)sqrt(dWidth*dWidth + dHeight*dHeight);
01919 
01920     // and from that calculate area of the box containing the bit of the
01921     // bit of the circle in the bbox
01922     INT32 Edge = (Diagonal * (100 - (GFill->Spec.Fountain.Padding * 2))) / 100;
01923 
01924     // Start point is the centre given by Corel.
01925     // This centre is percentage offsets from the centre of the object, i.e. (0,0) is
01926     // the centre of the bounding box.
01927     DocCoord Centre = DocCoord(BBox.lo.x + (Width / 2), BBox.lo.y + (Height / 2));
01928     INT32 OffX = (GFill->Spec.Fountain.Offset.x * Width) / 100;
01929     INT32 OffY = (GFill->Spec.Fountain.Offset.y * Height) / 100;
01930     Start.x = Centre.x + OffX;
01931     Start.y = Centre.y + OffY;
01932 
01933     // Find required radius of circle.
01934     double Radius = Edge / 2;
01935 
01936     // how far away is the centre of the fill from the centre of the bbox?
01937     double dOffX = OffX;
01938     double dOffY = OffY;
01939     double Dist = (INT32)sqrt(dOffX*dOffX + dOffY*dOffY);
01940 
01941     // and increase the radius by a bodge factor
01942     double BodgeFactor = 1 + (Dist / (double)(Diagonal / 2));
01943     Radius *= BodgeFactor;
01944     
01945     // End point is start point + radius
01946     if(IsSquare)
01947     {
01948         // angled thingy for square fills
01949         double Theta = GFill->Spec.Fountain.Angle;
01950         End.x = Start.x + ((MILLIPOINT)(Radius * cos(Theta)));
01951         End.y = Start.y + ((MILLIPOINT)(Radius * sin(Theta)));
01952         End2.x = Start.x + ((MILLIPOINT)(Radius * cos(Theta + PI/2)));
01953         End2.y = Start.y + ((MILLIPOINT)(Radius * sin(Theta + PI/2)));
01954     }
01955     else
01956     {
01957         // simple thingy for radial fills
01958         End.x = Start.x + ((MILLIPOINT) Radius);
01959         End.y = Start.y;
01960     }
01961 
01962     // Seems that we need to swap start and end colours...
01963 
01964     // Set the fill type according to these calculations.
01965     BOOL ok;
01966     if(IsSquare)
01967         ok = SetSquareFill(*EndColour, *StartColour, Start, End, End2);
01968 
01969     else
01970         ok = SetRadialFill(*EndColour, *StartColour, Start, End);
01971 
01972     return ok;  
01973 }
01974 
01975 
01976 /********************************************************************************************
01977 
01978 >   BOOL CMXImportFilter::SetAttributesBitmapFill(INT32 VectorReference, cmxiTiling *Tile)
01979 
01980     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
01981     Created:    19/08/96
01982     Inputs:     vector reference, tiling specification
01983     Returns:    error flag
01984     Purpose:    sets a bitmap fill from possible fillness in the CMX file...
01985 
01986 ********************************************************************************************/
01987 
01988 BOOL CMXImportFilter::SetAttributesBitmapFill(Node *pNode, INT32 VectorReference, cmxiTiling *Tile)
01989 {
01990     // check the vector fill reference
01991     if(VectorReference <= 0 || VectorReference > Data->NumProcedures)
01992         return SetNoFill(pNode);
01993 
01994     // see if we can get a position for it
01995     INT32 Position = Data->Procedures[VectorReference-1].Position;
01996     if(Position <= 0)
01997         return SetNoFill(pNode);
01998     
01999     // store the position of the file for later
02000     INT32 StartFilePos = Tell();
02001 
02002     // jump to the position of the vector fill procedure
02003     Seek(Position);
02004 
02005     // variable for getting the bitmap reference
02006     INT32 Jenny = -1;
02007 
02008     // and see if we can find a draw image command in there somewhere -- skip the header
02009     RIFFck hdr;
02010     pFile->read(&hdr, sizeof(hdr));
02011     // I'm not going to check the type of this chunk as corel specify one type, and put
02012     // another in the file. Stupid documentionness
02013     BOOL EndProcLoc = Tell() + hdr.ckSize;
02014 
02015     // run through the loop... what follows is a load of instructions
02016     TRACEUSER( "Ben", _T("searching commands in vector fill procedure:\n"));
02017     BOOL Done = FALSE;
02018     while(Done == FALSE)
02019     {
02020         // look at a command
02021         // get the current file position
02022         INT32 CommandEndFilePos = Tell();
02023 
02024         // read the command header
02025         CI_READDATA(CommandHeader, ch)
02026 
02027         // if the command thing is negative, we may need to fudge it if we're going 16 bitness
02028         if(ch.Code < 0 && !Is32Bit)
02029             ch.Code = 0 - ch.Code;
02030 
02031         CommandEndFilePos += ch.Size;           // get the file pos of the end of the instruction
02032 
02033         // is this a bit of a DrawImage command?
02034         if(ch.Code == cmxINSTR_DrawImage)
02035         {
02036             // yep -- read in it's data
02037             CI_READDATA(DrawImage, di)
02038 
02039             if(di.ImageFileReference1 > 0 && di.ImageFileReference1 <= Data->NumRImages)
02040             {
02041                 // found our bitmap image -- all done here
02042                 Jenny = di.ImageFileReference1;
02043                 break;      // don't bother looking at anything else
02044             }
02045         }
02046         else if(ch.Code == cmxINSTR_EndSection)
02047         {
02048             // the section finished -- stop looking now...
02049             break;
02050         }
02051 
02052         // finally, check that we're in the right position in the file for the next command
02053         if(Tell() != CommandEndFilePos)
02054             Seek(CommandEndFilePos);
02055 
02056         if(CommandEndFilePos >= EndProcLoc)
02057             break;
02058     }
02059     TRACEUSER( "Ben", _T("finished searching commands, ref = %d\n"), Jenny);
02060 
02061     // go back to where we were in the file
02062     Seek(StartFilePos);
02063 
02064     // now, did we get a bitmap reference? if not, give up now
02065     if(Jenny <= 0)
02066         return SetNoFill(pNode);
02067 
02068     // right then, get the bounding box for the object as we'll need this later
02069     DocRect BBox;
02070     if(!GetCorelBBox((NodeRenderableBounded *)pNode, &BBox))
02071         return FALSE;
02072 
02073     // get the coord things from the tiling info
02074     DocCoord StartPoint, EndPoint, EndPoint2;
02075     if(!GetTilingPoints(&BBox, Tile, &StartPoint, &EndPoint, &EndPoint2))
02076         return FALSE;
02077 
02078     // locate the bitmap thingy -- we know that the reference we have is OK
02079     if(!Data->RImages[Jenny-1].IsRImage())
02080         return SetNoFill(pNode);        // can't do that either without one of the RImages
02081     KernelBitmap *pBitmap = Data->RImages[Jenny-1].GetBitmap(this);
02082     if(pBitmap == 0)
02083         return SetNoFill(pNode);        // wasn't converted, oh dear
02084 
02085     // and set the fill (wow)
02086     return SetBitmapFill(pBitmap, StartPoint, EndPoint, EndPoint2);
02087 }
02088 
02089 
02090 /********************************************************************************************
02091 
02092 >   BOOL CMXImportFilter::SetAttributesTwoColourBitmapFill(Node *pNode, cmxiFillSpec *Fill)
02093 
02094     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02095     Created:    26/08/96
02096     Inputs:     node, fill spec
02097     Returns:    error flag
02098     Purpose:    sets a two colour contone fill
02099 
02100 ********************************************************************************************/
02101 
02102 BOOL CMXImportFilter::SetAttributesTwoColourBitmapFill(Node *pNode, cmxiFillSpec *pFill)
02103 {
02104     // right then, get the bounding box for the object as we'll need this later
02105     DocRect BBox;
02106     if(!GetCorelBBox((NodeRenderableBounded *)pNode, &BBox))
02107         return FALSE;
02108 
02109     // get the coord things from the tiling info
02110     DocCoord StartPoint, EndPoint, EndPoint2;
02111     if(!GetTilingPoints(&BBox, &pFill->Spec.TwoColourBitmap.Tile, &StartPoint, &EndPoint, &EndPoint2))
02112         return FALSE;
02113 
02114     // reverse the tiling thingys
02115     INT32 y0 = StartPoint.y;
02116     INT32 y1 = EndPoint2.y;
02117     StartPoint.y = y1;
02118     EndPoint2.y = y0;
02119     EndPoint.y = y1;
02120 
02121     // check the reference
02122     if(pFill->Spec.TwoColourBitmap.BitmapReference <= 0 || pFill->Spec.TwoColourBitmap.BitmapReference > Data->NumBitmaps)
02123         return SetNoFill(pNode);        // couldn't find the bitmap, go away, your mother was a hamster and your father smelled of elderberries
02124 
02125     // get the colours
02126     DocColour *pStartColour = GetColourFromReference(pFill->Spec.TwoColourBitmap.ForeColourReference);
02127     DocColour *pEndColour = GetColourFromReference(pFill->Spec.TwoColourBitmap.BackColourReference);
02128 
02129     // locate the bitmap thingy -- we know that the reference we have is OK
02130     KernelBitmap *pBitmap = Data->Bitmaps[pFill->Spec.TwoColourBitmap.BitmapReference - 1].CreateColouredCopy(this, pStartColour, pEndColour);
02131     if(pBitmap == 0)
02132         return SetNoFill(pNode);        // wasn't converted, oh dear
02133 
02134     // and set the fill and sod off back to the function we came from
02135     return SetBitmapFill(pBitmap, StartPoint, EndPoint, EndPoint2);
02136 }
02137 
02138 
02139 /********************************************************************************************
02140 
02141 >   BOOL CMXImportFilter::GetTilingPoints(DocRect *BBox, cmxiTiling *Tile, DocCoord *StartPoint, DocCoord *EndPoint, DocCoord *EndPoint2)
02142 
02143     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02144     Created:    19/08/96
02145     Inputs:     bbox of object, tiling struct, points to fill in
02146     Returns:    error flag
02147     Purpose:    works out points for the fill of a tiled thingy
02148 
02149 ********************************************************************************************/
02150 
02151 BOOL CMXImportFilter::GetTilingPoints(DocRect *BBox, cmxiTiling *Tile, DocCoord *StartPoint, DocCoord *EndPoint, DocCoord *EndPoint2)
02152 {
02153     if(Tile != 0)
02154     {
02155         // find the size of the tile
02156         INT32 SizeX = (INT32)(Tile->Width * Data->BaseScaleFactor);
02157         INT32 SizeY = (INT32)(Tile->Height * Data->BaseScaleFactor);
02158 
02159         // set to the top left + the first tile offset
02160         INT32 XPos = BBox->lo.x + ((SizeX * Tile->XOffset) / 100);
02161         INT32 YPos = BBox->hi.y - SizeY - ((SizeY * Tile->YOffset) / 100);
02162 
02163         // set the points
02164         *StartPoint = DocCoord(XPos,            YPos);
02165         *EndPoint   = DocCoord(XPos + SizeX,    YPos);
02166         *EndPoint2  = DocCoord(XPos,            YPos + SizeY);
02167     }
02168     else
02169     {
02170         // don't have a tile -- set things to fill the entire object
02171         *StartPoint = DocCoord(BBox->lo.x, BBox->lo.y);
02172         *EndPoint   = DocCoord(BBox->hi.x, BBox->lo.y);
02173         *EndPoint2  = DocCoord(BBox->lo.x, BBox->hi.y);
02174     }
02175 
02176     return TRUE;
02177 }
02178 
02179 
02180 /********************************************************************************************
02181 
02182 >   BOOL CMXImportFilter::SkipToPreviewBitmap(CCLexFile * pFile)
02183 
02184     Author:     Ben_Summers (Xara Group Ltd) <camelotdev@xara.com>
02185     Created:    28/08/96
02186     Inputs:     file
02187     Returns:    True if it is a RIFF format file and found the preview bitmap.
02188                 False if any problems are found or the file format is wrong.
02189     Purpose:    sees if there is a preview bitmap to fiddle with -- this will actually
02190                 work for any RIFF file thingy
02191 
02192 ********************************************************************************************/
02193 
02194 BOOL CMXImportFilter::SkipToPreviewBitmap(CCLexFile * pFile)
02195 {
02196     // beginning
02197     pFile->seekIn(0);
02198 
02199     // get header
02200     RIFFFile_Header hdr;
02201     pFile->read(&hdr, sizeof(hdr));
02202 
02203     // is it a form?
02204     if(hdr.CK.ckID != RIFFTYPE_RIFF)
02205         return FALSE;       // no thingy
02206 
02207     INT32 FileEnd = hdr.CK.ckSize;
02208     INT32 where = sizeof(hdr);
02209 
02210     // OK, look at the first few chunks
02211     for(INT32 togo = 4; togo > 0 && where < FileEnd; togo--)
02212     {
02213         // read the chunk header
02214         RIFFck ck;
02215         pFile->read(&ck, sizeof(ck));
02216 
02217         where += sizeof(ck) + ck.ckSize;
02218 
02219         // does this have the required type?
02220         if(ck.ckID == cmxRIFFCI_Thumbnail)
02221         {
02222             // yep, found it -- skip four bytes
02223             DWORD clipboardformat;
02224             pFile->read(&clipboardformat, sizeof(clipboardformat));
02225 
02226             return TRUE;        // found it
02227         }
02228 
02229         // next thingy
02230         pFile->seekIn(where);
02231     }
02232 
02233     // nothing found, mate
02234     return FALSE;
02235 }
02236 
02237 
02238 
02239 
02240 
02241 /********************************************************************************************
02242 
02243 >   void CMXImportFilter::SetNonTextAttributeIgnore()
02244 
02245     Author:     Claude_Quemerais (Xara Group Ltd) <camelotdev@xara.com>
02246     Created:    21/08/96
02247     Inputs:     none
02248     
02249     Purpose:    Set the non-text attribute to be ignored
02250 
02251 ********************************************************************************************/
02252 
02253 void CMXImportFilter::SetNonTextAttributeIgnore()
02254 {
02255     CurrentAttrs[ATTR_BAD_ID].Ignore = TRUE;        
02256     CurrentAttrs[ATTR_STROKECOLOUR].Ignore = TRUE;
02257     CurrentAttrs[ATTR_STROKETRANSP].Ignore = TRUE;
02258     CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = TRUE;
02259     CurrentAttrs[ATTR_TRANSPFILLGEOMETRY].Ignore = TRUE;
02260     CurrentAttrs[ATTR_FILLMAPPING].Ignore = TRUE;
02261     CurrentAttrs[ATTR_TRANSPFILLMAPPING].Ignore = TRUE;
02262     CurrentAttrs[ATTR_FILLEFFECT].Ignore = TRUE;
02263     CurrentAttrs[ATTR_LINEWIDTH].Ignore = TRUE;
02264     CurrentAttrs[ATTR_WINDINGRULE].Ignore = TRUE;
02265     CurrentAttrs[ATTR_JOINTYPE].Ignore = TRUE;
02266     CurrentAttrs[ATTR_QUALITY].Ignore = TRUE;
02267     CurrentAttrs[ATTR_DASHPATTERN].Ignore = TRUE;
02268     CurrentAttrs[ATTR_STARTCAP].Ignore = TRUE;
02269     CurrentAttrs[ATTR_STARTARROW].Ignore = TRUE;
02270     CurrentAttrs[ATTR_ENDARROW].Ignore = TRUE;
02271     CurrentAttrs[ATTR_MITRELIMIT].Ignore = TRUE;
02272     CurrentAttrs[ATTR_TXTFONTTYPEFACE].Ignore = TRUE;
02273     CurrentAttrs[ATTR_OVERPRINTLINE].Ignore = TRUE;
02274     CurrentAttrs[ATTR_OVERPRINTFILL].Ignore = TRUE;
02275     CurrentAttrs[ATTR_PRINTONALLPLATES].Ignore = TRUE;
02276     CurrentAttrs[ATTR_FIRST_FREE_ID].Ignore = TRUE;
02277     CurrentAttrs[ATTR_MOULD].Ignore = TRUE;
02278     CurrentAttrs[ATTR_ENDCAP].Ignore = TRUE;
02279 }
02280     
02281 /********************************************************************************************
02282 
02283 >   void CMXImportFilter::SetNonTextAttributeNotIgnore()
02284 
02285     Author:     Claude_Quemerais (Xara Group Ltd) <camelotdev@xara.com>
02286     Created:    21/08/96
02287     Inputs:     none
02288     
02289     Purpose:    Set the non-text attribute not to be ignored
02290 
02291 ********************************************************************************************/
02292 
02293 void CMXImportFilter::SetNonTextAttributeNotIgnore()
02294 {
02295     CurrentAttrs[ATTR_BAD_ID].Ignore = FALSE;       
02296     CurrentAttrs[ATTR_STROKECOLOUR].Ignore = FALSE;
02297     CurrentAttrs[ATTR_STROKETRANSP].Ignore = FALSE;
02298     CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = FALSE;
02299     CurrentAttrs[ATTR_TRANSPFILLGEOMETRY].Ignore = FALSE;
02300     CurrentAttrs[ATTR_FILLMAPPING].Ignore = FALSE;
02301     CurrentAttrs[ATTR_TRANSPFILLMAPPING].Ignore = FALSE;
02302     CurrentAttrs[ATTR_FILLEFFECT].Ignore = FALSE;
02303     CurrentAttrs[ATTR_LINEWIDTH].Ignore = FALSE;
02304     CurrentAttrs[ATTR_WINDINGRULE].Ignore = FALSE;
02305     CurrentAttrs[ATTR_JOINTYPE].Ignore = FALSE;
02306     CurrentAttrs[ATTR_QUALITY].Ignore = FALSE;
02307     CurrentAttrs[ATTR_DASHPATTERN].Ignore = FALSE;
02308     CurrentAttrs[ATTR_STARTCAP].Ignore = FALSE;
02309     CurrentAttrs[ATTR_STARTARROW].Ignore = FALSE;
02310     CurrentAttrs[ATTR_ENDARROW].Ignore = FALSE;
02311     CurrentAttrs[ATTR_MITRELIMIT].Ignore = FALSE;
02312     CurrentAttrs[ATTR_TXTFONTTYPEFACE].Ignore = FALSE;
02313     CurrentAttrs[ATTR_OVERPRINTLINE].Ignore = FALSE;
02314     CurrentAttrs[ATTR_OVERPRINTFILL].Ignore = FALSE;
02315     CurrentAttrs[ATTR_PRINTONALLPLATES].Ignore = FALSE;
02316     CurrentAttrs[ATTR_FIRST_FREE_ID].Ignore = FALSE;
02317     CurrentAttrs[ATTR_MOULD].Ignore = FALSE;
02318     CurrentAttrs[ATTR_ENDCAP].Ignore = FALSE;
02319 }
02320 /********************************************************************************************
02321 
02322 >   void CMXImportFilter::SetTextAttributeIgnore()
02323 
02324     Author:     Claude_Quemerais (Xara Group Ltd) <camelotdev@xara.com>
02325     Created:    21/08/96
02326     Inputs:     none
02327     
02328     Purpose:    Set the text attributes to be ignored
02329 
02330 ********************************************************************************************/
02331 
02332 void CMXImportFilter::SetTextAttributeIgnore()
02333 {
02334     CurrentAttrs[ATTR_TXTFONTTYPEFACE].Ignore = TRUE;       
02335     CurrentAttrs[ATTR_TXTBOLD].Ignore = TRUE;
02336     CurrentAttrs[ATTR_TXTITALIC].Ignore = TRUE;
02337     CurrentAttrs[ATTR_TXTASPECTRATIO].Ignore = TRUE;
02338     CurrentAttrs[ATTR_TXTJUSTIFICATION].Ignore = TRUE;
02339     CurrentAttrs[ATTR_TXTTRACKING].Ignore = TRUE;
02340     CurrentAttrs[ATTR_TXTUNDERLINE].Ignore = TRUE;
02341     CurrentAttrs[ATTR_TXTFONTSIZE].Ignore = TRUE;
02342     CurrentAttrs[ATTR_TXTSCRIPT].Ignore = TRUE;
02343     CurrentAttrs[ATTR_TXTBASELINE].Ignore = TRUE;
02344     CurrentAttrs[ATTR_TXTLINESPACE].Ignore = TRUE;
02345 
02346 }
02347     
02348 /********************************************************************************************
02349 
02350 >   void CMXImportFilter::SetTextAttributeNotIgnore()
02351 
02352     Author:     Claude_Quemerais (Xara Group Ltd) <camelotdev@xara.com>
02353     Created:    21/08/96
02354     Inputs:     none
02355     
02356     Purpose:    Set the text attribute not to be ignored
02357 
02358 ********************************************************************************************/
02359 
02360 void CMXImportFilter::SetTextAttributeNotIgnore()
02361 {
02362     CurrentAttrs[ATTR_TXTFONTTYPEFACE].Ignore = FALSE;      
02363     CurrentAttrs[ATTR_TXTBOLD].Ignore = FALSE;
02364     CurrentAttrs[ATTR_TXTITALIC].Ignore = FALSE;
02365     CurrentAttrs[ATTR_TXTASPECTRATIO].Ignore = FALSE;
02366     CurrentAttrs[ATTR_TXTJUSTIFICATION].Ignore = FALSE;
02367     CurrentAttrs[ATTR_TXTTRACKING].Ignore = FALSE;
02368     CurrentAttrs[ATTR_TXTUNDERLINE].Ignore = FALSE;
02369     CurrentAttrs[ATTR_TXTFONTSIZE].Ignore = FALSE;
02370     CurrentAttrs[ATTR_TXTSCRIPT].Ignore = FALSE;
02371     CurrentAttrs[ATTR_TXTBASELINE].Ignore = FALSE;
02372     CurrentAttrs[ATTR_TXTLINESPACE].Ignore = FALSE;
02373     
02374 }

Generated on Sat Nov 10 03:44:45 2007 for Camelot by  doxygen 1.4.4