drawfltr.cpp

Go to the documentation of this file.
00001 // $Id: drawfltr.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 
00099 // An input filter for importing RISC OS Draw format files.
00100 
00101 
00102 #include "camtypes.h"
00103 #include "drawfltr.h"
00104 
00105 #include <ctype.h>
00106 
00107 #include <afxdlgs.h>
00108 
00109 //#include "pathname.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 #include "paper.h"
00115 #include "nodepath.h"
00116 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 //#include "tim.h"
00118 #include "lineattr.h"
00119 #include "progress.h"           // for the progress indicator
00120 //#include "tim.h"
00121 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00124 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00125 #include "page.h"
00126 //#include "trans2d.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00127 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00128 
00129 
00130 DECLARE_SOURCE("$Revision: 1282 $");
00131 
00132 
00133 CC_IMPLEMENT_DYNAMIC(AcornDrawFilter, VectorFilter)
00134 
00135 
00136 
00137 #define DRAWOBJECT_FONTTABLE           (0) 
00138 #define DRAWOBJECT_TEXT                (1) 
00139 #define DRAWOBJECT_PATH                (2) 
00140 #define DRAWOBJECT_SPRITE              (5)
00141 #define DRAWOBJECT_GROUP               (6)
00142 #define DRAWOBJECT_TAGGED              (7)
00143 #define DRAWOBJECT_TEXTAREA            (9)
00144 #define DRAWOBJECT_TEXTCOLUMN         (10)
00145 #define DRAWOBJECT_OPTIONS            (11)
00146 #define DRAWOBJECT_TRANSFORMEDTEXT    (12)
00147 #define DRAWOBJECT_TRANSFORMEDSPRITE  (13)
00148 
00149 #define DRAWOBJECT_ERROR              (-1)  // => Error reading object header
00150 
00151 
00152 
00153 
00154 #define DRAWTAG_ENDOFPATH              (0)
00155 #define DRAWTAG_MOVETO                 (2)
00156 #define DRAWTAG_CLOSESUBPATH           (5)
00157 #define DRAWTAG_LINETO                 (8)
00158 #define DRAWTAG_CURVETO                (6)
00159 
00160 
00161 
00162 #define SIZEOF_MOVETO                 (12)
00163 #define SIZEOF_CLOSESUBPATH            (4)
00164 #define SIZEOF_LINETO                 (12)
00165 #define SIZEOF_CURVETO                (28)
00166 
00167 
00168 
00169 
00170 
00171 #define DRAW_TRANSPARENT      (0xFFFFFFFF)
00172 
00173 
00174 
00175 /********************************************************************************************
00176 
00177 >   class DrawColour
00178 
00179     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00180     Created:    08/12/93
00181     Purpose:    Mirrors the representation of a colour as used in Acorn Draw files.
00182     SeeAlso:    DrawPathStyle; DashPatternHeader
00183 
00184 ********************************************************************************************/
00185 
00186 class DrawColour
00187 {
00188 public:
00189     union
00190     {
00191         struct
00192         {
00193             BYTE Reserved : 8;
00194             BYTE Red      : 8;
00195             BYTE Green    : 8;
00196             BYTE Blue     : 8;
00197         } Component;
00198         UINT32 ColourValue;
00199     } Data;
00200 };
00201 
00202 
00203 /********************************************************************************************
00204 
00205     typedef DrawPathStyle
00206 
00207     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00208     Created:    08/12/93
00209     Purpose:    Holds the style information for a path as used in Acorn Draw files.
00210     SeeAlso:    DrawColour; DashPatternHeader
00211 
00212 ********************************************************************************************/
00213 
00214 typedef union
00215 {
00216     UINT32 Value;
00217     struct
00218     {
00219         UINT32 Join        : 2;
00220         UINT32 EndCap      : 2;
00221         UINT32 StartCap    : 2;
00222         UINT32 WindingRule : 1;
00223         UINT32 DashPresent : 1;
00224         UINT32 Reserved    : 8;
00225         UINT32 CapWidth    : 8;
00226         UINT32 CapLength   : 8;
00227     } Data;
00228 } DrawPathStyle;
00229 
00230 
00231 /********************************************************************************************
00232 
00233 >   class DashPatternHeader
00234 
00235     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00236     Created:    08/12/93
00237     Purpose:    The header for the dash pattern structure contained in Acorn Draw files.
00238                 It is usually followed by a series of dash and gap lengths in the file.
00239     SeeAlso:    DrawColourl; DrawPathStyle
00240 
00241 ********************************************************************************************/
00242 
00243 class DashPatternHeader
00244 {
00245 public:
00246     UINT32 Offset;
00247     UINT32 NumElements;
00248 };
00249 
00250 
00251 /********************************************************************************************
00252 
00253 >   class DrawPathElement
00254 
00255     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00256     Created:    08/12/93
00257     Purpose:    Used to load in a path element from a Draw file.  Not all of the 'Coords'
00258                 array is always used - it depends on the path element.
00259     SeeAlso:    DrawPathHeader
00260 
00261 ********************************************************************************************/
00262 
00263 class DrawPathElement
00264 {
00265 public:
00266     UINT32 Tag;
00267     DocCoord Coords[3]; 
00268 };
00269 
00270 
00271 /********************************************************************************************
00272 
00273 >   class DrawPathHeader
00274 
00275     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00276     Created:    08/12/93
00277     Purpose:    Used to load in the header information for a path object in a Draw file.
00278                 It holds details on the fill and line colours, the line width, and the
00279                 style of the path.
00280     SeeAlso:    DrawPathElement; DrawColour; DrawPathStyle
00281 
00282 ********************************************************************************************/
00283 
00284 class DrawPathHeader
00285 {
00286 public:
00287     DrawColour      FillColour;
00288     DrawColour      LineColour;
00289     UINT32          LineWidth;
00290     DrawPathStyle   Style;
00291 };
00292 
00293 
00294 /********************************************************************************************
00295 
00296 >   AcornDrawFilter::AcornDrawFilter()
00297 
00298     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00299     Created:    18/11/93
00300     Purpose:    Filter constructor - this initialises the default attributes and the
00301                 input buffer.
00302 
00303 ********************************************************************************************/
00304 
00305 AcornDrawFilter::AcornDrawFilter()
00306 {
00307     // Set up filter descriptions.
00308     FilterName.Load(_R(IDT_DRAW_FILTERNAME));
00309     FilterInfo.Load(_R(IDT_DRAW_FILTERINFO));
00310     FilterID = FILTERID_ACORN_DRAW;
00311 
00312 #ifndef STANDALONE
00313     Flags.CanImport = TRUE;
00314     Flags.CanExport = FALSE;
00315 #else
00316     Flags.CanImport = FALSE;
00317     Flags.CanExport = FALSE;
00318 #endif
00319 
00320 #if 0
00321     // No attributes yet
00322     DefLineWidthAttr = NULL;
00323     DefLineColAttr = NULL;
00324     DefFillColAttr = NULL;
00325 #endif
00326 
00327     // No buffer yet
00328     DataBuf = NULL;
00329     DataBufSize = 0;
00330 };
00331 
00332 
00333 /********************************************************************************************
00334 
00335 >   AcornDrawFilter::~AcornDrawFilter()
00336 
00337     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00338     Created:    18/11/93
00339     Purpose:    Destructor for the filter - this deallocates the input buffer.
00340 
00341 ********************************************************************************************/
00342 
00343 AcornDrawFilter::~AcornDrawFilter()
00344 {
00345     // Clean up our input buffer
00346     CCFree(DataBuf);
00347 }
00348 
00349 
00350 /********************************************************************************************
00351 
00352 >   BOOL AcornDrawFilter::Init()
00353 
00354     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00355     Created:    18/11/93
00356     Returns:    Always TRUE at the moment.
00357     Purpose:    Initialise the filter (attaches a DrawOILFilter object).
00358     SeeAlso:    DrawOILFilter
00359 
00360 ********************************************************************************************/
00361 
00362 BOOL AcornDrawFilter::Init()
00363 {
00364     // Get the OILFilter object
00365     pOILFilter = new DrawOILFilter(this);
00366     if (pOILFilter == NULL)
00367         return FALSE;
00368 
00369     // All ok
00370     return TRUE;
00371 }
00372 
00373 /********************************************************************************************
00374 
00375 >   virtual BOOL AcornDrawFilter::IsDefaultDocRequired(const TCHAR* pcszPathName)
00376 
00377     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00378     Created:    16/10/95
00379     Inputs:     pcszPathName    pointer to the pathname to check
00380     Returns:    TRUE if the filter requires a default document, FALSE if not.
00381     Purpose:    Works out if opening a file of this type requires a default document to be
00382                 loaded. If the file format supplies the document then return FALSE otherwise
00383                 return TRUE. An example would be opening a bitmap file. This has no document
00384                 defined in the file format and so we need to laod the default document before
00385                 importing the bitmap into this file.
00386                 In this version we return TRUE as either this format has no page size or
00387                 nobody has implemented it yet.
00388     SeeAlso:    Filter; Filter::IsDefaultDocRequired; CCamDoc::OnOpenDocument;
00389     SeeAlso:    FilterFamily::DoImport; Filter::DoImport;
00390 
00391 ********************************************************************************************/
00392 
00393 BOOL AcornDrawFilter::IsDefaultDocRequired(const TCHAR* pcszPathName)
00394 {
00395     // No need to check the pathname, just return TRUE as all currently known bitmap filters
00396     // will require the default document.
00397     return TRUE;
00398 }   
00399 
00400 
00401 /********************************************************************************************
00402 
00403 >   INT32 AcornDrawFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, 
00404                                        UINT32 HeaderSize, UINT32 FileSize)
00405 
00406     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00407     Created:    21/03/94
00408     Inputs:     Filename - name of the file.
00409                 HeaderStart - Address of the first few bytes of the file.
00410                 HeaderSize - the number of bytes in the header pointed to by FileStart.
00411                 FileSize - the size of the whole file, in bytes.
00412     Returns:    Compatibility: 0 => Not a Draw file; 10 => It is a Draw file
00413     Purpose:    Analyse a file to see if it is an Acorn Draw file - at present this
00414                 is done by checking to see if the first four bytes are "Draw".
00415     SeeAlso:    AcornDrawFilter
00416 
00417 ********************************************************************************************/
00418 
00419 INT32 AcornDrawFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, 
00420                                    UINT32 HeaderSize, UINT32 FileSize)
00421 
00422 {
00423 PORTNOTE("byteorder", "TODO: Check byte ordering")
00424     if (camStrncmp((char *) HeaderStart, "Draw", 4) == 0)
00425     {
00426         // It's a Draw file.
00427         return 10;
00428     }
00429     
00430     // It's not a Draw file.
00431     return 0;
00432 }
00433 
00434 
00435 /********************************************************************************************
00436 
00437 >   BOOL AcornDrawFilter::PrepareToImport()
00438 
00439     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00440     Created:    22/02/94
00441     Returns:    TRUE if it succeeds, FALSE if not.
00442     Purpose:    Sets up the Draw filter so it can read in a Draw file.
00443 
00444 ********************************************************************************************/
00445 
00446 BOOL AcornDrawFilter::PrepareToImport()
00447 {
00448     // Get a default set of attributes for ink objects.
00449     if (!SetUpCurrentAttrs())
00450         return FALSE;
00451 
00452     // Shouldn't have a data buffer at this point
00453     ENSURE(DataBuf == NULL, "DataBuf is non-NULL in PrepareToImport()");
00454 
00455     // No objects read yet
00456     HeaderSize = 0;
00457     DataSize = 0;
00458 
00459     // Get a Diskfile object
00460     DrawFile = NULL;
00461 
00462     // Ok so far
00463     return TRUE;
00464 }
00465 
00466 
00467 /********************************************************************************************
00468 
00469 >   void AcornDrawFilter::CleanUpAfterImport()
00470 
00471     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00472     Created:    24/02/94
00473     Purpose:    Delete dynamic objects used in the import process.
00474     SeeAlso:    AcornDrawFilter::PrepareToImport; AcornDrawFilter::DoImport
00475 
00476 ********************************************************************************************/
00477 
00478 void AcornDrawFilter::CleanUpAfterImport()
00479 {
00480     DeleteCurrentAttrs();
00481     DrawFile = NULL;
00482     CCFree(DataBuf);
00483     DataBuf = NULL;
00484     DataBufSize = 0;
00485 }
00486 
00487 
00488 /********************************************************************************************
00489 
00490 >   BOOL AcornDrawFilter::DoImport(SelOperation *Op, CCLexFile* pFile, 
00491                                Document *DestDoc, BOOL AutoChosen, ImportPosition* Pos,
00492                                KernelBitmap** ppImportedBitmap, DocCoord* pPosTranslate, String_256* URL)
00493 
00494     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00495     Created:    18/11/93
00496     Inputs:     Op - pointer to the operation that this read process is associated with.
00497                 pFile - The file that we are trying to import
00498                 DestDoc - pointer to the document to insert the Draw file data into.
00499                 AutoChosen - 
00500                 Pos -
00501                 ppImportedBitmap - this is used mainly in the bitfltr.cpp for the HTML
00502                 import filter. HTMLFilter::DoImport() needs a pointer to a kernel bitmap
00503                 to set the background bitmap up into Camelot.
00504                 pPosTranslate - This is used too by the HTMLFilter in order to do a formatting.
00505                 URL - original URL of the imported file
00506     Returns:    TRUE if the read was successful, FALSE if not.
00507     Purpose:    Import the named Acorn draw file into the specified document.
00508                 As yet, only path and group objects are handled.  Tagged objects are
00509                 handled correctly, so, e.g. TableMate files can be loaded by Camelot
00510                 (although the results are not very interesting).
00511                 Currently, the data is always positioned on the first page of the first
00512                 spread in the first chapter.
00513                 If the read is successful, the End() function of the 'Op' operation is
00514                 called, otherwise it is not called.
00515     Errors:     Unable to open file, corrupted document tree found.
00516 
00517 ********************************************************************************************/
00518 
00519 BOOL AcornDrawFilter::DoImport(SelOperation *Op, CCLexFile* pFile, 
00520                                Document *DestDoc, BOOL AutoChosen, ImportPosition* Pos,
00521                                KernelBitmap** ppImportedBitmap, DocCoord* pPosTranslate, String_256* URL)
00522 {
00523     // Let's get ready
00524     if (!PrepareToImport())
00525         return FALSE;
00526 
00527     // Make sure that there is a layer to put the bitmap onto
00528     if (!MakeSureLayerExists(DestDoc))
00529         // There is no layer and one could not be made, so we will have to fail
00530         return FALSE;
00531 
00532     // Find the layer on the first page of this document...
00533     pLayer = GetActiveLayer(DestDoc);
00534     ENSURE(pLayer != NULL, "Spread has no active layer"); 
00535     
00536     // pNode is where new objects will go - they all go into a group so the user
00537     // can easily drag the imported Draw file around.  They can then ungroup it afterwards
00538     // if they want.
00539     NodeGroup *pDrawGroup = new NodeGroup;
00540     ERRORIF(pDrawGroup == NULL, _R(IDT_DRAW_NOMEMORY), FALSE);
00541     pNode = pDrawGroup;
00542         
00543     Spread *pSpread;
00544 
00545     if (Pos == NULL)
00546     {
00547         // For now, position Draw objects on 1st page of spread 1
00548 PORTNOTE("spread", "Multi-spread warning!")
00549         pSpread = GetFirstSpread(DestDoc);
00550         pPage = (Page *) pSpread->FindFirstPageInSpread();
00551         ENSURE(pPage->IsKindOf(CC_RUNTIME_CLASS(Page)),
00552                "AcornDrawFilter::Read(): Could not find first Page");
00553         
00554         // Use bottom left of page as origin
00555         DocRect PageRect = pPage->GetPageRect();
00556         Origin = PageRect.lo;
00557     }
00558     else
00559     {
00560         pSpread = Pos->pSpread;
00561         Origin = Pos->Position;
00562     }
00563     
00564     // No complex path initially
00565     ComplexPath = FALSE;
00566 
00567     // Make a note of the disk file
00568     DrawFile = pFile;
00569 
00570     // Disable exceptions and error reporting for this file - we'll do it ourselves
00571     DrawFile->SetReportErrors(FALSE);
00572     DrawFile->SetThrowExceptions(FALSE);
00573 
00574     // Find out the size of the file, in bytes.
00575     INT32 filesize = DrawFile->Size();
00576         
00577     // Initialise
00578     eof = FALSE;
00579         
00580     // Set the progress indicator, this next bit might take a while.
00581     String_64 ImportMessage(_R(IDT_IMPORTMSG_ACORNDRAW));
00582     ImportMessage = GetImportProgressString(pFile, _R(IDT_IMPORTMSG_ACORNDRAW));
00583     BeginSlowJob(filesize, TRUE, &ImportMessage);
00584 
00585     BytesRead = 0;
00586     LastProgressUpdate = 0;
00587 
00588     // Find out details on the file
00589     ReadFileHeader();
00590 
00591     // Check that this is an Acorn Draw file...the first four characters in the file
00592     // should be "Draw".  If we've been chosen automatically, then don't bother as we've
00593     // already checked this.
00594     if (DrawFile->eof() || (!AutoChosen && (camStrncmp(FileHeader.Ident, "Draw", 4) != 0)))
00595     {
00596         // Could not find the ident header - close the file, and return error.
00597         EndSlowJob();
00598         CleanUpAfterImport();
00599         ERROR(_R(IDT_DRAW_NOTADRAWFILE), FALSE);
00600     }
00601     
00602     // Remember file errors
00603     BOOL Error = FALSE;
00604 
00605     // Process each object in the file
00606     do 
00607     {
00608         // Read and process each object
00609         if (ReadObjectHeader())
00610         {
00611             // Header read ok so there is another object to process
00612             if (!ProcessObject())
00613                 // Unable to process object - set error flag
00614                 Error = TRUE;
00615         }
00616     }
00617     while ((BytesRead < filesize) && !Error);
00618     
00619     // All work has been completed . . .
00620     EndSlowJob();
00621     
00622     // All done
00623     BOOL Failed = Error && (BytesRead < filesize);
00624 
00625     // Free up dynamic objects used for import
00626     CleanUpAfterImport();
00627 
00628     // If the load failed for any reason, delete the subtree we have created; otherwise
00629     // graft it into the tree.
00630     if (Failed)
00631     {
00632         // Failed - delete the sub-tree we just created, free the buffer, and return error.
00633         pDrawGroup->CascadeDelete();
00634         delete pDrawGroup;
00635         return FALSE;
00636     }
00637     else
00638     {
00639         // It worked - add the node into the tree
00640         
00641         // Remember current bounding rectangle of the group
00642         DocRect BoundsRect = pDrawGroup->GetBoundingRect(TRUE);
00643         
00644         if (Pos != NULL)
00645         {
00646             // It should be centred on the given position...
00647             DocCoord Centre;
00648             Centre.x = (BoundsRect.lo.x + BoundsRect.hi.x) / 2;
00649             Centre.y = (BoundsRect.lo.y + BoundsRect.hi.y) / 2;
00650 
00651             Trans2DMatrix Xlate(Pos->Position.x - Centre.x, Pos->Position.y - Centre.y);
00652             pDrawGroup->Transform(Xlate);
00653         }
00654                 
00655         // Insert the node and invalidate its region
00656         if (!Op->DoInsertNewNode(pDrawGroup, pSpread, TRUE))
00657         {
00658             // It didn't work - delete the sub-tree we just created
00659             pDrawGroup->CascadeDelete();
00660             delete pDrawGroup;
00661             pDrawGroup = NULL;
00662         }
00663     
00664     }
00665 
00666     // All ok
00667     return TRUE;
00668 }
00669 
00670 /********************************************************************************************
00671 
00672 >   BOOL AcornDrawFilter::ReadFileHeader()
00673 
00674     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00675     Created:    18/11/93
00676     Returns:    TRUE if the read is successful, FALSE if an error was encountered.
00677     Purpose:    Read the header block of an Acorn Draw file.
00678     SeeAlso:    AcornDrawFilter::ReadObjectHeader
00679     Scope:      Private
00680 
00681 ********************************************************************************************/
00682 
00683 BOOL AcornDrawFilter::ReadFileHeader()
00684 {
00685     DrawFile->read(&FileHeader, sizeof(FileHeader));
00686     BytesRead += sizeof(FileHeader);
00687     return TRUE;
00688 }
00689 
00690 /********************************************************************************************
00691 
00692 >   BOOL AcornDrawFilter::ReadObjectHeader()
00693 
00694     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00695     Created:    18/11/93
00696     Returns:    TRUE if the header was read ok, FALSE if not.
00697     Purpose:    This function reads in the header of a Draw object from the input file,
00698                 and stores the result in the ObjectHeader member variable.
00699                 Using the data in the header it then sets up the HeaderSize and DataSize
00700                 member variables correctly.  It is not ok just to use sizeof(ObjectHeader)
00701                 as this is not always accurate because some objects in Draw files has
00702                 stupid headers which are smaller than the standard size, so we have to
00703                 compensate for this.  In such cases we also have to rewind the file so we
00704                 are in the correct position to read in the data following the header.
00705     Errors:     If the EOF is found.
00706     SeeAlso:    AcornDrawFilter::ReadObjectData; AcornDrawFilter::ReadFileHeader
00707     Scope:      Private
00708 
00709 ********************************************************************************************/
00710 
00711 BOOL AcornDrawFilter::ReadObjectHeader()
00712 {
00713     // Set default header size
00714     FilePos BeforePos = DrawFile->tell();
00715 
00716     HeaderSize = sizeof(ObjectHeader);
00717 
00718     DrawFile->read(&ObjectHeader, sizeof(ObjectHeader));
00719 
00720     BytesRead += sizeof(ObjectHeader);
00721 
00722     FilePos AfterPos = DrawFile->tell();
00723 
00724     if ((UINT32) (AfterPos-BeforePos) != sizeof(ObjectHeader))
00725     {
00726         ERROR3_PF(("Header bytes read - actual: %d, planned: %d", (AfterPos-BeforePos), sizeof(ObjectHeader)));
00727         // If EOF found, then an error has occured
00728         ERROR1(FALSE, _R(IDT_DRAW_BADSYNTAX));
00729     }
00730 
00731     // Check for silly objects that don't have a bounding box, and move the input pointer
00732     // back to cope with this.
00733     switch (ObjectHeader.Type)
00734     {
00735         case DRAWOBJECT_FONTTABLE:
00736             // Move back over the bounding box fields (which don't really exist)
00737             FilePos Pos = DrawFile->tellIn();
00738 
00739             // Bounding box fields take up 16 bytes in Acorn Draw files.
00740             DrawFile->seekIn(Pos - 16);
00741             BytesRead -= 16;
00742 
00743             // Adjust header size
00744             HeaderSize -= 16;
00745             break;
00746     }
00747 
00748     DataSize = ObjectHeader.Size - HeaderSize;
00749 
00750     // If eof not found, then no error
00751     return TRUE;
00752 }
00753 
00754 /********************************************************************************************
00755 
00756 >   BOOL AcornDrawFilter::ProcessObject()
00757 
00758     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00759     Created:    19/11/93
00760     Returns:    TRUE if the object was processed with no errors, FALSE if not.
00761     Purpose:    Routes the object data to the appropriate function to be processed,
00762                 according to the tag in the object's header data.
00763                 If the object is not understood, then the data is simply discarded.
00764     Errors:     -
00765     SeeAlso:    AcornDrawFilter::ProcessPath; AcornDrawFilter::ProcessGroup;
00766                 AcornDrawFilter::ProcessTaggedObject; AcornDrawFilter::SkipObject
00767     Scope:      Private
00768 
00769 ********************************************************************************************/
00770 
00771 BOOL AcornDrawFilter::ProcessObject()
00772 {
00773     if (BytesRead > (LastProgressUpdate + 2048))
00774     {
00775         LastProgressUpdate = BytesRead;
00776         if (!ContinueSlowJob(BytesRead))
00777             return FALSE;
00778     }
00779 
00780     switch (ObjectHeader.Type)
00781     {
00782         case DRAWOBJECT_PATH:       return ProcessPath();
00783         case DRAWOBJECT_GROUP:      return ProcessGroup();
00784         case DRAWOBJECT_TAGGED:     return ProcessTaggedObject();
00785         default:                    return SkipObject();
00786     }
00787 }
00788 
00789 /********************************************************************************************
00790 
00791 >   BOOL AcornDrawFilter::ProcessPath()
00792 
00793     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00794     Created:    18/11/93
00795     Returns:    TRUE if the path object is read and converted ok, FALSE if not.
00796     Purpose:    Read in the data for a Draw path object, and convert it to an equivalent
00797                 Camelot NodePath object, and add it to the node pointed to by the pNode
00798                 member variable.
00799     Errors:     File reading error, out of memory.
00800     SeeAlso:    AcornDrawFilter::ProcessObject
00801     Scope:      Private
00802 
00803 ********************************************************************************************/
00804 
00805 BOOL AcornDrawFilter::ProcessPath()
00806 {
00807     // Attempt to read the data for this object
00808     if (!ReadObjectData())
00809         return FALSE;
00810 
00811     // Construct the path and add it to our group node...
00812 
00813     // Create a new NodePath pbject
00814     NodePath *pPath = new NodePath(pNode, LASTCHILD);
00815     if ((pPath == NULL) || (!pPath->SetUpPath()))
00816     {
00817         // Couldn't initialise path - delete path (if created) and return error.
00818         delete pPath;
00819         ERROR(_R(IDT_DRAW_NOMEMORY), FALSE);
00820     }
00821 
00822     // Position tag at start of path.
00823     pPath->InkPath.FindStartOfPath();
00824 
00825     // Examine path header info
00826     DrawPathHeader *pHeader = (DrawPathHeader *) DataBuf;
00827 
00828     // Find first path element
00829     DrawPathElement *pElement = (DrawPathElement *) (pHeader + 1);
00830 
00831     // Skip dash pattern if present
00832     if (pHeader->Style.Data.DashPresent)
00833     {
00834         DashPatternHeader *pDashPattern = (DashPatternHeader *) pElement;
00835         pElement = (DrawPathElement *) 
00836          ( ((ADDR) pElement) + sizeof(DashPatternHeader) + (4 * pDashPattern->NumElements) );
00837     }
00838 
00839     // Process path elements until no more data is left.
00840     UINT32 BytesUsed = 0;
00841 
00842     INT32 Tag = (pElement->Tag) & 0xFF;
00843 
00844     while (Tag != DRAWTAG_ENDOFPATH)
00845     {
00846         switch (Tag)
00847         {
00848             case DRAWTAG_MOVETO:
00849                 BytesUsed = SIZEOF_MOVETO;
00850 
00851                 TransformCoord(pElement->Coords[0]);
00852 
00853                 // Insert a moveto into the path
00854                 if (!pPath->InkPath.InsertMoveTo(pElement->Coords[0]))
00855                     // Not enough dynamic heap to insert the moveto command
00856                     goto NoMemory;
00857                 break;
00858 
00859             case DRAWTAG_LINETO:
00860                 BytesUsed = SIZEOF_LINETO;
00861 
00862                 TransformCoord(pElement->Coords[0]);
00863 
00864                 // Insert a lineto into the path
00865                 if (!pPath->InkPath.InsertLineTo(pElement->Coords[0]))
00866                     // Not enough dynamic heap to insert the lineto command
00867                     goto NoMemory;
00868                 break;
00869 
00870             case DRAWTAG_CURVETO:
00871                 BytesUsed = SIZEOF_CURVETO;
00872 
00873                 TransformCoord(pElement->Coords[0]);
00874                 TransformCoord(pElement->Coords[1]);
00875                 TransformCoord(pElement->Coords[2]);
00876 
00877                 // Insert a curveto into the path
00878                 if (!pPath->InkPath.InsertCurveTo(pElement->Coords[0], 
00879                                                   pElement->Coords[1], pElement->Coords[2]))
00880                     // Not enough dynamic heap to insert the curveto command
00881                     goto NoMemory;
00882                 break;
00883 
00884             case DRAWTAG_CLOSESUBPATH:
00885                 BytesUsed = SIZEOF_CLOSESUBPATH;
00886 
00887                 // Terminate sub-path
00888                 if (!pPath->InkPath.CloseSubPath())
00889                     // Not enough dynamic heap to insert the final element of the path
00890                     goto NoMemory;
00891                             
00892                 break;
00893 
00894             default:
00895                 // Don't understand this element!
00896                 ERROR1(FALSE, _R(IDT_DRAW_BADSYNTAX));
00897         }
00898 
00899         // Move pointer onto next path element
00900         pElement = (DrawPathElement *) (((ADDR) pElement) + BytesUsed);
00901 
00902         Tag = (pElement->Tag) & 0xFF;
00903     }
00904 
00905     // check that the path is OK
00906     if(!pPath->InkPath.EnsureValid())
00907     {
00908         // no, it's completely knackered
00909         pPath->UnlinkNodeFromTree();
00910         delete pPath;
00911         // don't error about it.
00912         return TRUE;
00913     }
00914 
00915     // Use the path header to set the attributes on this path
00916     AddAttributes(pPath, pHeader);
00917 
00918     // Terminate path properly.
00919     pPath->InvalidateBoundingRect();
00920                 
00921     // All ok
00922     return TRUE;
00923 
00924 NoMemory:
00925     // Error - Out of memory while reading Draw file
00926     
00927     // Destroy any half-created paths
00928     if (pPath != NULL)
00929     {
00930         pPath->CascadeDelete();
00931         delete pPath;
00932     }   
00933     // Set the error for the caller to report
00934     ERROR(_R(IDT_DRAW_NOMEMORY), FALSE);
00935 }
00936 
00937 /********************************************************************************************
00938 
00939 >   BOOL AcornDrawFilter::ProcessGroup()
00940 
00941     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00942     Created:    18/11/93
00943     Returns:    -
00944     Purpose:    Read in a Draw group object, which can be an arbitrary group of Draw objects,
00945                 possibly including other groups.  A NodeGroup object is constructed from
00946                 the group's data and added to the node pointed to by the member variable
00947                 pNode.
00948     Errors:     Out of memory, error processing objects in the group, unexpected EOF.
00949     SeeAlso:    AcornDrawFilter::ProcessObject
00950     Scope:      Private
00951 
00952 ********************************************************************************************/
00953 
00954 #define DRAW_GROUPNAMESIZE (12)
00955 
00956 BOOL AcornDrawFilter::ProcessGroup()
00957 {
00958     // Remembers file read errors
00959     BOOL Error = FALSE;
00960 
00961     // Skip past the group name
00962     DrawFile->seekIn(DRAW_GROUPNAMESIZE, ios::cur);
00963     BytesRead += DRAW_GROUPNAMESIZE;
00964 
00965     // Create a group node, and make pNode point to it, so that all objects in the group
00966     // are attached to it.
00967     NodeGroup *pGroup = new NodeGroup(pNode, LASTCHILD);
00968     if (pGroup == NULL)
00969     {
00970         // Not enough heap to create group
00971         ERROR(_R(IDT_DRAW_NOMEMORY), FALSE);
00972     }
00973 
00974     Node *pOldNode = pNode;
00975     pNode = pGroup;
00976 
00977     // Work out where the end of the group is
00978     FilePos EndPos = DrawFile->tellIn();
00979     DataSize -= DRAW_GROUPNAMESIZE;
00980     EndPos += DataSize;
00981 
00982     // Read (and process) each object in the group, until the end of group or end of file
00983     // is found.
00984     do 
00985     {
00986         // Read in and process the next object
00987         if (!(ReadObjectHeader() && ProcessObject()))
00988             Error = TRUE;
00989 
00990     } while (!DrawFile->eof() && (DrawFile->tellIn() < EndPos));
00991 
00992         
00993     // Restore the node pointer to the parent of this group
00994     pNode = pOldNode;
00995 
00996     // If EOF found, then the group was truncated, so return error.
00997     // Also return error if object reading failed in any way.
00998     if (Error)
00999         // Error has already been set
01000         return FALSE;
01001 
01002     if (DrawFile->eof())
01003         ERROR1(FALSE, _R(IDT_DRAW_BADSYNTAX));
01004         
01005     // Must have worked
01006     return TRUE;
01007 }
01008 
01009 #define DRAW_TAGSIZE (4)
01010 
01011 /********************************************************************************************
01012 
01013 >   BOOL AcornDrawFilter::ProcessTaggedObject()
01014 
01015     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01016     Created:    19/11/93
01017     Returns:    TRUE if the tagged object is read and process ok, FALSE if not.
01018     Purpose:    Read in and process a tagged object from a Draw file.
01019                 A tagged object is a normal object with some arbitrary data following it.
01020                 This function can handle the tagged object being a group which itself
01021                 contains tagged objects, and so on.
01022     Errors:     Out of memory, error processing the tagged object.
01023     SeeAlso:    AcornDrawFilter::ProcessObject; AcornDrawFilter::ReadObjectHeader
01024     Scope:      Private
01025 
01026 ********************************************************************************************/
01027 
01028 BOOL AcornDrawFilter::ProcessTaggedObject()
01029 {
01030     // Remembers file read errors
01031     BOOL Error = FALSE;
01032 
01033     // Skip past the object tag
01034     DrawFile->seekIn(DRAW_TAGSIZE, ios::cur);
01035     BytesRead += DRAW_TAGSIZE;
01036 
01037     // Work out where the end of the tagged object is
01038     FilePos EndPos = DrawFile->tellIn();
01039     DataSize -= DRAW_TAGSIZE;
01040     EndPos += DataSize;
01041 
01042     // Read (and process) the object
01043     if (!(ReadObjectHeader() && ProcessObject()))
01044         // Something went wrong so return error
01045         return FALSE;
01046 
01047     // Skip the word-aligned data following the object
01048     DrawFile->seekIn(EndPos);
01049     BytesRead = EndPos;
01050 
01051     // All ok
01052     return TRUE;
01053 }
01054 
01055 /********************************************************************************************
01056 
01057 >   BOOL AcornDrawFilter::SkipObject()
01058 
01059     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01060     Created:    18/11/93
01061     Returns:    TRUE always at present.
01062     Purpose:    Skips past the data for this object, usually because the object is not
01063                 supported by this filter and/or Camelot.
01064     SeeAlso:    AcornDrawFilter::ProcessObject
01065     Scope:      Private
01066 
01067 ********************************************************************************************/
01068 
01069 BOOL AcornDrawFilter::SkipObject()
01070 {
01071     if (IsUserName("Tim"))
01072     {
01073         TRACE( _T("Skipping unsupported object (type %d, size %d)\n"),
01074                 ObjectHeader.Type, 
01075                 ObjectHeader.Size);
01076     }
01077 
01078     // Skip the number of bytes specified in the current object's header
01079     FilePos Pos = DrawFile->tellIn();
01080     Pos += DataSize;
01081     DrawFile->seekIn(Pos);
01082     BytesRead = Pos;
01083 
01084     // No error checking yet
01085     return TRUE;
01086 }
01087 
01088 /********************************************************************************************
01089 
01090 >   BOOL AcornDrawFilter::ReadObjectData()
01091 
01092     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01093     Created:    18/11/93
01094     Returns:    TRUE if the data was read ok, FALSE if not.
01095     Purpose:    Read in the data for a Draw object.  The data is stored in the buffer
01096                 pointed to by the member variable DataBuf.  If the buffer is not big enough,
01097                 it is automagically expanded.
01098     Errors:     Out of memory.
01099     SeeAlso:    AcornDrawFilter::ReadObjectHeader
01100     Scope:      Private
01101 
01102 ********************************************************************************************/
01103 
01104 BOOL AcornDrawFilter::ReadObjectData()
01105 {
01106     // Obtain a buffer to read the data into, if we haven't got one already
01107     if (DataSize > DataBufSize)
01108     {
01109         // Buffer is not big enough - try to expand it.
01110         // Don't overwrite DataBuf pointer unless we know the realloc succeeds, otherwise
01111         // we won't be able to free the old buffer if it fails.
01112         ADDR NewBuf = (ADDR) CCRealloc(DataBuf, DataSize);
01113 
01114         // Failed to expand buffer - return error.
01115         ERRORIF(NewBuf == NULL, _R(IDT_DRAW_NOMEMORY), FALSE);
01116 
01117         // Buffer was expanded ok - update the buffer pointer/size variables.
01118         DataBufSize = DataSize;
01119         DataBuf = NewBuf;
01120     }
01121 
01122     // To get this far, we must have a buffer big enough to hold the object, so read it in...
01123     // NB we check that we read the correct number of bytes.
01124     FilePos BeforePos = DrawFile->tell();
01125     DrawFile->read(DataBuf, DataSize);
01126     BytesRead += DataSize;
01127     FilePos AfterPos = DrawFile->tell();
01128 
01129     if ((UINT32) (AfterPos-BeforePos) != DataSize)
01130     {
01131         ERROR3_PF(("Bytes read - actual: %d, planned: %d", (AfterPos-BeforePos), DataSize));
01132         // If EOF found, then an error has occured
01133         ERROR1(FALSE, _R(IDT_DRAW_BADSYNTAX));
01134     }
01135 
01136     // Ok if we got here.
01137     return TRUE;
01138 }
01139 
01140 
01141 /********************************************************************************************
01142 
01143 >   BOOL AcornDrawFilter::AddAttributes(NodePath *pPath, DrawPathHeader *pHeader)
01144 
01145     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01146     Created:    18/11/93
01147     Inputs:     pPath - pointer to the NodePath object to add attributes to.
01148                 pHeader - pointer to the Draw file object header which describes the path
01149                 attributes.
01150     Returns:    TRUE if the attributes were added ok, FALSE if not.
01151     Purpose:    Add attributes to the path object specified.  The attributes are optimised
01152                 so that if they are the same as the document's default attributes, they are
01153                 not applied.
01154                 The attributes applied are line and fill colour, and line style.
01155     Errors:     Fails (returns FALSE) if not enough memory to add attributes.
01156     Scope:      Private
01157 
01158 ********************************************************************************************/
01159 
01160 BOOL AcornDrawFilter::AddAttributes(NodePath *pPath, DrawPathHeader *pHeader)
01161 {
01162     // Add attributes to the path, if they are different from the default...
01163 
01164     // First set the current attributes.
01165 
01166     // Fill colour
01167     if (pHeader->FillColour.Data.ColourValue == DRAW_TRANSPARENT)
01168     {
01169         pPath->InkPath.IsFilled = FALSE;
01170     }
01171     else
01172     {
01173         pPath->InkPath.IsFilled = TRUE;
01174 
01175         DocColour FillColour(pHeader->FillColour.Data.Component.Red, 
01176                              pHeader->FillColour.Data.Component.Green,
01177                              pHeader->FillColour.Data.Component.Blue);
01178         
01179         if (!SetFillColour(FillColour))
01180             return FALSE;
01181     }
01182 
01183     // Line colour
01184     if (pHeader->LineColour.Data.ColourValue == DRAW_TRANSPARENT)
01185     {
01186         if (!SetLineColour(DocColour(COLOUR_TRANS)))
01187             return FALSE;
01188     }
01189     else
01190     {
01191         DocColour LineColour(pHeader->LineColour.Data.Component.Red, 
01192                              pHeader->LineColour.Data.Component.Green,
01193                              pHeader->LineColour.Data.Component.Blue);
01194 
01195         if (!SetLineColour(LineColour))
01196             return FALSE;
01197     }
01198                 
01199     // Line width
01200 
01201     // Convert from Draw units (1/640 of a point) to Camelot units (millipoints_
01202     // Hence it involves multiplying by 1000/640, which equates to 25/16.
01203     pHeader->LineWidth *= 25;
01204     pHeader->LineWidth /= 16;
01205 
01206     if (!SetLineWidth(pHeader->LineWidth))
01207         return FALSE;
01208 
01209     // Now add attributes if they are different from the defaults.
01210 
01211     // If not filled, then set the ignore bit on the fill attribute.
01212     if (!pPath->InkPath.IsFilled)
01213         CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = TRUE;
01214 
01215     // Add attributes to the path, if they are different from the default...
01216     BOOL Result = AttributeManager::ApplyBasedOnDefaults(pPath, CurrentAttrs);
01217 
01218     // Enable the fill attribute again
01219     CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = FALSE;
01220 
01221     // Return success or failure
01222     return Result;
01223 }
01224 
01225 /********************************************************************************************
01226 
01227 >   BOOL AcornDrawFilter::DoExport(Operation*, CCLexFile*, PathName*, Document*, BOOL)
01228 
01229     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01230     Created:    28/03/94
01231     Inputs:     As base class version.
01232     Returns:    FALSE.
01233     Purpose:    None; this is a dummy function as we don't export in Acorn Draw format (yet).
01234     SeeAlso:    Filter::DoExport; Filter
01235 
01236 ********************************************************************************************/
01237 
01238 BOOL AcornDrawFilter::DoExport(Operation*, CCLexFile*, PathName*, Document*, BOOL)
01239 {
01240     // We don't export in Draw format
01241     return FALSE;
01242 }
01243 

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