metafilt.cpp

Go to the documentation of this file.
00001 // $Id: metafilt.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 // Metafile filter code
00100 
00101 #include "camtypes.h"
00102 #include "metafilt.h"
00103 
00104 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 //#include "tim.h"
00106 //#include "andy.h"
00107 //#include "rik.h"
00108 #include "gdimagic.h"
00109 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 #include "camelot.h"
00111 #include "nodepath.h"
00112 //#include "pathname.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "oilfiles.h"
00114 #include "csrstack.h"
00115 #include "progress.h"        
00116 #include "page.h"
00117 //#include "trans2d.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 //#include "resource.h"
00121 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 //#include "accures.h"
00123 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00124 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00125 //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00126 #include "layer.h"
00127 #include "osrndrgn.h"
00128 #include "camvw.h"
00129 #include "wbitmap.h"
00130 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00131 #include "nodebmp.h"
00132 #include "nodetxts.h"
00133 #include "nodeelip.h"
00134 
00135 #include "clipext.h"    // External clipboard
00136 //#include "selop.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00137 #include "metaview.h"
00138 //#include "richard2.h"
00139 
00140 CC_IMPLEMENT_DYNCREATE(MetaFileClipMap, ClipboardMapping)
00141 
00142 
00143 // ------------------------------------------------------------------------------------------
00144 
00145 // There now follows a certain amount of unpleasantness, which allows us to access
00146 // 16-bit Windows' GDI records, which is what we get when reading 16-bit metafiles.
00147 
00148 typedef short INT16;
00149 typedef WORD  UINT16;
00150 
00151 #ifdef _MSC_VER
00152     // Make sure structures correspond to Win16 equivalents.
00153     // (pack to 1 byte boundaries)
00154     #pragma pack(push, 1)
00155 
00156     typedef struct
00157     {
00158         INT16           lbStyle;
00159         COLORREF        lbColor;
00160         INT16           lbHatch;
00161     } LOGBRUSH_16;
00162 
00163     typedef struct
00164     {
00165         INT16 x;
00166         INT16 y;
00167     } POINT_16;
00168 
00169     typedef struct
00170     {
00171         INT16           lopnStyle;
00172         POINT_16        lopnWidth;
00173         COLORREF        lopnColor;
00174     } LOGPEN_16;
00175 
00176     typedef struct
00177     {
00178         BYTE        peRed;
00179         BYTE        peGreen;
00180         BYTE        peBlue;
00181         BYTE        peFlags;
00182     } PALETTEENTRY_16;
00183     
00184     typedef struct
00185     {
00186         WORD        palVersion;
00187         WORD        palNumEntries;
00188         PALETTEENTRY_16        palPalEntry[1];
00189     } LOGPALETTE_16;
00190 
00191     #pragma pack(pop)
00192 #else
00193     #error Dont know how to pack structures with this compiler!
00194 #endif // _MSC_VER
00195 
00196 
00197 /********************************************************************************************
00198 
00199 <   HandleType
00200 
00201     Comment:    Used to identify the type of a GDI handle in a HandleTable entry.
00202     SeeAlso:    HandleRecord; HandleTable; MetaFileFilter
00203 
00204 ********************************************************************************************/
00205 
00206 typedef enum
00207 {
00208     HANDLE_NONE,
00209     HANDLE_PEN,
00210     HANDLE_BRUSH,
00211     HANDLE_PALETTE,
00212     HANDLE_PATTERNBRUSH,
00213     HANDLE_FONTINDIRECT,
00214     HANDLE_REGION
00215 } HandleType;
00216 
00217 
00218 /********************************************************************************************
00219 
00220 >   class HandleRecord
00221 
00222     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00223     Created:    28/03/94
00224     Purpose:    Table entries used by the HandleTable class.
00225                 This class currently supports pen handles and brush handles.  Other
00226                 handles (e.g. Fonts) will be added as necessary.
00227     SeeAlso:    HandleTable; MetaFileFilter
00228 
00229 ********************************************************************************************/
00230 
00231 class HandleRecord
00232 {
00233 public:
00234     HandleType  Type;
00235     DocColour   Colour;
00236     MILLIPOINT  PenWidth;
00237     LOGFONT_16* pFont;
00238 };
00239     
00240 
00241 
00242 /********************************************************************************************
00243 
00244 >   class HandleTable
00245 
00246     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00247     Created:    28/03/94
00248     Purpose:    Provide a mirror of the table of handles maintained by GDI when importing
00249                 a MetaFile.  This is necessary because, given a GDI handle, it is not
00250                 possible to ask GDI what kind of object it is, and hence work out e.g. what
00251                 kind of pen/brush it is.
00252                 This class therefore creates, selects, and deletes handle objects in the
00253                 same way that GDI would (see EnumMetafile help in SDK documentation for
00254                 further details...possibly).
00255                 At the moment, this HandleTable only supports pens and brushes.
00256     SeeAlso:    HandleRecord; MetaFileFilter
00257 
00258 ********************************************************************************************/
00259 
00260 class HandleTable
00261 {
00262 public:
00263     HandleTable(MetaFileFilter *);
00264     ~HandleTable();
00265 
00266     // Function to create objects
00267     BOOL CreatePen(LOGPEN_16 *);
00268     BOOL CreateBrush(LOGBRUSH_16 *);
00269     BOOL CreatePalette(LOGPALETTE_16 *);
00270     BOOL CreatePatternBrush(WORD*);
00271     BOOL CreateFontIndirect(LOGFONT_16*);
00272     BOOL CreateRegion(WORD*);
00273 
00274     // Select and delete them
00275     BOOL SelectObject(INT32 Index);
00276     BOOL DeleteObject(INT32 Index);
00277 
00278 private:
00279     INT32 FindFreeSlot();
00280 
00281     // The filter associated with this HandleTable.
00282     MetaFileFilter *Context;
00283 
00284     // Pointer to the handle table.
00285     HandleRecord *Handles;
00286 
00287     // Number of entries in the handle table.
00288     INT32 TableSize;
00289 };
00290 
00291 /********************************************************************************************
00292 
00293 >   HandleTable::HandleTable(MetaFileFilter *pFilter)
00294 
00295     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00296     Created:    28/03/94
00297     Purpose:    Initialises the HandleTable.  The table initially contains no entries.
00298     SeeAlso:    HandleTable
00299 
00300 ********************************************************************************************/
00301 
00302 HandleTable::HandleTable(MetaFileFilter *pFilter)
00303 {
00304     Handles = NULL;
00305     TableSize = 0;
00306     Context = pFilter;
00307 }
00308 
00309 
00310 /********************************************************************************************
00311 
00312 >   HandleTable::~HandleTable()
00313 
00314     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00315     Created:    28/03/94
00316     Purpose:    Deinitialises a handle table; deallocates the handle table.
00317     SeeAlso:    HandleTable
00318 
00319 ********************************************************************************************/
00320 HandleTable::~HandleTable()
00321 {
00322     CCFree(Handles);
00323     Handles = NULL;
00324     TableSize = 0;
00325 }
00326 
00327 
00328 // Constants used in HandleTable member functions:
00329 
00330 // Number of entries to increase handle table by when it runs out of space.
00331 static const INT32 TableGranularity = 10;
00332 
00333 // Value that implies an error occurred while getting a slot index.
00334 static const INT32 BAD_SLOT = -1;
00335 
00336 
00337 
00338 /********************************************************************************************
00339 
00340 >   INT32 HandleTable::FindFreeSlot()
00341 
00342     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00343     Created:    28/03/94
00344     Returns:    Index of first free slot in the handle table, or BAD_SLOT if there is no
00345                 free slot.
00346     Purpose:    Find the index of the first free slot available in the handle table.  If no
00347                 free handles are found, the table is expanded and the index of the first
00348                 new slot is returned. If it is not possible to expand the table (out of
00349                 memerory) then BAD_SLOT is returned.
00350     Errors:     Out of memory.
00351     SeeAlso:    HandleTable
00352 
00353 ********************************************************************************************/
00354 INT32 HandleTable::FindFreeSlot()
00355 {
00356     INT32 Slot;
00357 
00358     // Search the existing table for blanks
00359     for (Slot = 0; Slot < TableSize; Slot++)
00360     {
00361         if (Handles[Slot].Type == HANDLE_NONE)
00362             return Slot;
00363     }
00364 
00365     // Didn't find a free slot - get some more memory and return the first slot we get.
00366 
00367     INT32 NewTableSize = TableSize + TableGranularity;
00368 
00369     // If no slots yet, then allocate a table, otherwise expand the existing table
00370     HandleRecord *NewHandles;
00371     if (Handles == NULL)
00372         NewHandles = (HandleRecord *) CCMalloc(NewTableSize * sizeof(HandleRecord));
00373     else
00374         NewHandles = (HandleRecord *) CCRealloc(Handles, NewTableSize * sizeof(HandleRecord));
00375 
00376     // Did that work?
00377     if (NewHandles == NULL)
00378     {
00379         // No more memory available, but error state set by ccmalloc
00380         return BAD_SLOT;
00381     }
00382 
00383     // Initialise the new slots
00384     for (Slot = TableSize; Slot < NewTableSize; Slot++)
00385     {
00386         NewHandles[Slot].Type = HANDLE_NONE;
00387 
00388         // This bizarre syntax of 'new' allows us to call the constructor for an object
00389         // that has already been allocated.  We need to do this otherwise all the 
00390         // DocColour objects in the handle table are not initialised.
00391         // The constructors are not called because we just CCMalloc() the block of memory,
00392         // because we want to be able to resize the block (using CCRealloc).
00393         new(&NewHandles[Slot].Colour) DocColour;
00394     }
00395 
00396     // Remember the first slot
00397     Slot = TableSize;
00398 
00399     // Update handle table variables
00400     Handles   = NewHandles;
00401     TableSize = NewTableSize;
00402 
00403     // Return the first new slot
00404     return Slot;
00405 }
00406 
00407 /********************************************************************************************
00408 
00409 >   BOOL HandleTable::CreatePen(LOGPEN_16 *pPen)
00410 
00411     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00412     Created:    28/03/94
00413     Inputs:     pPen - the logical pen information for this pen. 
00414                     (See LOGPEN in Win16 SDK Help)
00415     Returns:    TRUE if handle was created ok, FALSE if not.
00416     Purpose:    Create a handle for the specified pen in the HandleTable, and store
00417                 the pen information in this.
00418     Errors:     Out of memory.
00419     SeeAlso:    HandleTable::CreateBrush
00420 
00421 ********************************************************************************************/
00422 BOOL HandleTable::CreatePen(LOGPEN_16 *pPen)
00423 {
00424     INT32 Style = pPen->lopnStyle;
00425     COLORREF Col = (COLORREF) pPen->lopnColor;
00426 
00427     // Get a new slot to put this pen in
00428     INT32 Slot = FindFreeSlot();
00429 
00430     if (Slot == BAD_SLOT)
00431         // Could not create this pen
00432         return FALSE;
00433 
00434     Handles[Slot].Type = HANDLE_PEN;
00435 
00436     switch (Style)
00437     {
00438         case PS_SOLID:
00439         case PS_INSIDEFRAME:
00440             Handles[Slot].Colour = DocColour(GetRValue(Col), GetGValue(Col), GetBValue(Col));
00441             break;
00442 
00443         case PS_NULL:
00444             Handles[Slot].Colour = DocColour(COLOUR_TRANS);
00445             break;
00446 
00447         default:
00448             ENSURE(FALSE, "Unknown pen style in metafile!");
00449             ERROR(_R(IDT_BAD_METAFILE), FALSE);
00450     }
00451 
00452     // Scale pen width to document coordinates.
00453     DocCoord PenSize(pPen->lopnWidth.x, 0);
00454     Context->ScaleCoord(&PenSize);
00455     Handles[Slot].PenWidth = PenSize.x;
00456 
00457     // All ok
00458     return TRUE;
00459 }
00460 
00461 
00462 /********************************************************************************************
00463 
00464 >   BOOL HandleTable::CreateBrush(LOGBRUSH_16 *pBrush)
00465 
00466     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00467     Created:    28/03/94
00468     Inputs:     pBrush - the logical brush information for this brush.
00469                     (See LOGBRUSH in Win16 SDK Help)
00470     Returns:    TRUE if handle was created ok, FALSE if not.
00471     Purpose:    Create a handle for the specified brush in the HandleTable, and store
00472                 the brush information in this.
00473     Errors:     Out of memory.
00474     SeeAlso:    HandleTable::CreatePen
00475 
00476 ********************************************************************************************/
00477 BOOL HandleTable::CreateBrush(LOGBRUSH_16 *pBrush)
00478 {
00479     INT32 Style = pBrush->lbStyle;
00480     COLORREF Col = (COLORREF) pBrush->lbColor;
00481 
00482     // Get a new slot to put this pen in
00483     INT32 Slot = FindFreeSlot();
00484 
00485     if (Slot == BAD_SLOT)
00486         // Could not create this pen
00487         return FALSE;
00488 
00489     Handles[Slot].Type = HANDLE_BRUSH;
00490 
00491     switch (Style)
00492     {
00493         case BS_SOLID:
00494             Handles[Slot].Colour = DocColour(GetRValue(Col), GetGValue(Col), GetBValue(Col));
00495             break;
00496 
00497         case BS_NULL:
00498             Handles[Slot].Colour = DocColour(COLOUR_TRANS);
00499             break;
00500 
00501         default:
00502             ENSURE(FALSE, "Unknown brush style in metafile!");
00503             ERROR(_R(IDT_BAD_METAFILE), FALSE);
00504     }
00505 
00506     // All ok
00507     return TRUE;
00508 }
00509 
00510 
00511 /********************************************************************************************
00512 
00513 >   BOOL HandleTable::CreatePalette(LOGPALETTE_16 *)
00514 
00515     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00516     Created:    18/5/95
00517     Returns:    TRUE if it worked, FALSE if there was a problem
00518     Purpose:    Creates a Palette object ready for use
00519 
00520 ********************************************************************************************/
00521 BOOL HandleTable::CreatePalette(LOGPALETTE_16 *)
00522 {
00523     // Get a new slot to put this pen in
00524     INT32 Slot = FindFreeSlot();
00525 
00526     // Could not create this Palette
00527     if (Slot == BAD_SLOT)
00528         return FALSE;
00529 
00530     // Say what this is
00531     Handles[Slot].Type = HANDLE_PALETTE;
00532 
00533     // return Happy
00534     return TRUE;
00535 }
00536 
00537 
00538 /********************************************************************************************
00539 
00540 >   BOOL HandleTable::CreatePatternBrush(WORD*)
00541 
00542     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00543     Created:    18/5/95
00544     Returns:    TRUE if it worked, FALSE if there was a problem
00545     Purpose:    Creates a PatternBrush object ready for use
00546 
00547 ********************************************************************************************/
00548 BOOL HandleTable::CreatePatternBrush(WORD*)
00549 {
00550     // Get a new slot to put this pen in
00551     INT32 Slot = FindFreeSlot();
00552 
00553     // Could not create this Palette
00554     if (Slot == BAD_SLOT)
00555         return FALSE;
00556 
00557     // Say what this is
00558     Handles[Slot].Type = HANDLE_PATTERNBRUSH;
00559 
00560     // return Happy
00561     return TRUE;
00562 }
00563 
00564 
00565 /********************************************************************************************
00566 
00567 >   BOOL HandleTable::CreateFontIndirect(LOGFONT_16* pNewFont)
00568 
00569     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00570     Created:    18/5/95
00571     Inputs:     pNewFont - the font we are creating
00572     Returns:    TRUE if it worked, FALSE if there was a problem
00573     Purpose:    Creates a Font object ready for use
00574 
00575 ********************************************************************************************/
00576 BOOL HandleTable::CreateFontIndirect(LOGFONT_16* pNewFont)
00577 {
00578     // Get a new slot to put this pen in
00579     INT32 Slot = FindFreeSlot();
00580 
00581     // Could not create this Palette
00582     if (Slot == BAD_SLOT)
00583         return FALSE;
00584 
00585     // Say what this is
00586     Handles[Slot].Type = HANDLE_FONTINDIRECT;
00587     Handles[Slot].pFont = pNewFont;
00588 
00589     // return Happy
00590     return TRUE;
00591 }
00592 
00593 
00594 /********************************************************************************************
00595 
00596 >   BOOL HandleTable::CreateRegion(WORD*)
00597 
00598     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00599     Created:    18/5/95
00600     Returns:    TRUE if it worked, FALSE if there was a problem
00601     Purpose:    Creates a Region object ready for use
00602 
00603 ********************************************************************************************/
00604 BOOL HandleTable::CreateRegion(WORD*)
00605 {
00606     // Get a new slot to put this pen in
00607     INT32 Slot = FindFreeSlot();
00608 
00609     // Could not create this Palette
00610     if (Slot == BAD_SLOT)
00611         return FALSE;
00612 
00613     // Say what this is
00614     Handles[Slot].Type = HANDLE_REGION;
00615 
00616     // return Happy
00617     return TRUE;
00618 }
00619 
00620 
00621 /********************************************************************************************
00622 
00623 >   BOOL HandleTable::SelectObject(INT32 Index)
00624 
00625     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00626     Created:    28/03/94
00627     Inputs:     Index - the index of the handle to select.
00628     Returns:    TRUE if the handle was selected ok; FALSE if not.
00629     Purpose:    Mimic the selection of a GDI object.  This function will update the relevant
00630                 status variables in the associated MetaFileFilter object.  
00631     Errors:     Bad index handle (i.e. specified handle does not exist)
00632     SeeAlso:    HandleTable::DeleteObject
00633 
00634 ********************************************************************************************/
00635 BOOL HandleTable::SelectObject(INT32 Index)
00636 {
00637     // Sanity check
00638     if ((Index < 0) || (Index >= TableSize))
00639     {
00640         // Out of range index
00641         if (IsUserName("Rik"))
00642             TRACE( _T("Tried to select out of range object\n"));
00643         ERROR(_R(IDT_BAD_METAFILE), FALSE);
00644     }
00645 
00646     // Try to select the object.
00647     switch (Handles[Index].Type)
00648     {
00649         case HANDLE_NONE:
00650             // No such object
00651             if (IsUserName("Rik"))
00652                 TRACE( _T("Tried to select non-existent object\n"));
00653             return FALSE;
00654 
00655         case HANDLE_PEN:
00656             Context->SetLineColour(Handles[Index].Colour);
00657             Context->SetLineWidth(Handles[Index].PenWidth);
00658             break;
00659 
00660         case HANDLE_BRUSH:
00661             Context->SetFillColour(Handles[Index].Colour);
00662             break;
00663 
00664         case HANDLE_PALETTE:
00665             break;
00666 
00667         case HANDLE_PATTERNBRUSH:
00668             break;
00669 
00670         case HANDLE_FONTINDIRECT:
00671             Context->SetLogicalFont(Handles[Index].pFont);
00672             break;
00673     
00674         case HANDLE_REGION:
00675             break;
00676 
00677         default:
00678             ENSURE(FALSE, "Bad metafile handle type!");
00679             ERROR(_R(IDT_BAD_METAFILE), FALSE);
00680     }
00681 
00682     // To get here we must have selected the object ok
00683     return TRUE;
00684 }
00685 
00686 
00687 /********************************************************************************************
00688 
00689 >   BOOL HandleTable::DeleteObject(INT32 Index)
00690 
00691     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00692     Created:    28/03/94
00693     Inputs:     Index - index of the handle object to delete from the table/
00694     Returns:    TRUE if handle deleted ok; FALSE if not.
00695     Purpose:    Deletes a handle from the Handle table.  The index of this handle should
00696                 no longer be used (unless, of course, it is reallocated to a new handle).
00697     Errors:     Bad index handle (i.e. specified handle does not exist)
00698     SeeAlso:    HandleTable::SelectObject
00699 
00700 ********************************************************************************************/
00701 BOOL HandleTable::DeleteObject(INT32 Index)
00702 {
00703     // Sanity check
00704     if ((Index < 0) || (Index >= TableSize))
00705     {
00706         // Out of range index
00707         if (IsUserName("Rik"))
00708             TRACE( _T("Tried to delete out of range object\n"));
00709         return FALSE;
00710     }
00711 
00712     // Try to select the object.
00713     switch (Handles[Index].Type)
00714     {
00715         case HANDLE_NONE:
00716             // No such object
00717             if (IsUserName("Rik"))
00718                 TRACE( _T("Tried to delete non-existent object\n"));
00719             return FALSE;
00720 
00721         case HANDLE_PEN:
00722         case HANDLE_BRUSH:
00723         case HANDLE_PALETTE:
00724         case HANDLE_PATTERNBRUSH:
00725         case HANDLE_FONTINDIRECT:
00726         case HANDLE_REGION:
00727             Handles[Index].Type = HANDLE_NONE;
00728             break;
00729 
00730         default:
00731             ENSURE(FALSE, "Bad metafile handle type!");
00732             ERROR(_R(IDT_BAD_METAFILE), FALSE);
00733     }
00734 
00735     // To get here we must have deleted the object ok
00736     return TRUE;
00737 }
00738 
00739 
00740 /********************************************************************************************
00741 
00742 >   MetaFileClipMap::MetaFileClipMap(ClipboardMappingType TheType, Filter *TheFilter,
00743                                         InternalClipboardFormat *TheInternalDataType,
00744                                         UINT32 TheExternalDataType,
00745                                         UINT32 ThePriority)
00746     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00747     Created:    16/4/95
00748 
00749     Inputs:     TheType - 1 (import), 2 (export), or 3 (import and export)
00750 
00751                 TheFilter - The filter which can apply this conversion
00752 
00753                 TheInternalDatatType - An object defining the internal data type
00754                 (see cliptype.h)
00755 
00756                 TheExternalDataType - A Windows CF_ constant defining the external
00757                 clipboard data type which will be imported/exported.
00758 
00759                 ThePriority - An integer indicating the priority of this mapping.
00760                 The highest available priority mapping will be used in order to
00761                 retain as much information in the data as possible. See
00762                 docs\howtouse\ExtClip.doc for details of the existing mappings.
00763 
00764     Purpose:    Constructs a clipboard mapping with the ExternalClipboard
00765                 manager. This mapping info describes a filter which is able to import
00766                 data from or export data to a windows clipboard in some way.
00767 
00768     Notes:      DON'T call the constructor - call CreateAndRegister
00769 
00770     SeeAlso:    MetaFileClipMap::CreateAndRegister
00771 
00772 ********************************************************************************************/
00773 MetaFileClipMap::MetaFileClipMap(ClipboardMappingType TheType, Filter *TheFilter,
00774                                     InternalClipboardFormat &TheInternalDataType,
00775                                     UINT32 TheExternalDataType,
00776                                     UINT32 ThePriority)
00777                 : ClipboardMapping(TheType, TheFilter, TheInternalDataType,
00778                                     TheExternalDataType, ThePriority)
00779 {
00780 }
00781 
00782 
00783 
00784 /********************************************************************************************
00785 
00786 >   static void MetaFileClipMap::CreateAndRegister(ClipboardMappingType TheType, Filter *TheFilter,
00787                                                 InternalClipboardFormat &TheInternalDataType,
00788                                                 UINT32 TheExternalDataType,
00789                                                 UINT32 ThePriority)
00790     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00791     Created:    16/4/95
00792 
00793     Inputs:     ImportOrExport - TRUE == Import, FALSE == Export
00794 
00795                 TheFilter - The filter which can apply this conversion
00796 
00797                 TheInternalDatatType - An object defining the internal data type
00798                 (see cliptype.h)
00799 
00800                 TheExternalDataType - A Windows CF_ constant defining the external
00801                 clipboard data type which will be imported/exported.
00802 
00803                 ThePriority - An integer indicating the priority of this mapping.
00804                 The highest available priority mapping will be used in order to
00805                 retain as much information in the data as possible. See
00806                 docs\howtouse\ExtClip.doc for details of the existing mappings.
00807 
00808     Purpose:    Constructs and registers a clipboard mapping with the ExternalClipboard
00809                 manager. This mapping info describes a filter which is able to import
00810                 data from or export data to a windows clipboard in some way.
00811 
00812 ********************************************************************************************/
00813 void MetaFileClipMap::CreateAndRegister(ClipboardMappingType TheType, Filter *TheFilter,
00814                                         InternalClipboardFormat &TheInternalDataType,
00815                                         UINT32 TheExternalDataType,
00816                                         UINT32 ThePriority)
00817 {
00818     MetaFileClipMap *Mapping = new MetaFileClipMap(TheType, TheFilter,
00819                                                     TheInternalDataType,
00820                                                     TheExternalDataType,
00821                                                     ThePriority);
00822     if (Mapping == NULL)
00823         InformError();
00824     else
00825         ExternalClipboard::RegisterDataType(Mapping);
00826 }
00827 
00828 
00829 
00830 /********************************************************************************************
00831 
00832 >   virtual BOOL MetaFileClipMap::HandleImport(SelOperation *Caller,
00833                                                 HANDLE ClipboardData,
00834                                                 InternalClipboard *Dest)
00835     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00836     Created:    20/4/95
00837 
00838     Inputs:     Caller - The operation within which this method is being called
00839                 ClipboardData - The result of calling GetClipboardData for your datatype
00840                 Dest - The InternalClipboard (document) to import the data into.
00841 
00842     Returns:    TRUE for success
00843 
00844     Purpose:    Calls the parent filter as appropriate to import the given data from
00845                 the external clipboard.
00846 
00847 ********************************************************************************************/
00848 BOOL MetaFileClipMap::HandleImport(SelOperation *Caller,
00849                                     HANDLE ClipboardData, InternalClipboard *Dest)
00850 {
00851     BOOL ok = FALSE;
00852 
00853     // Get a scratch file - if TMP isn't set, this will try for c:\temp.
00854     // The filename will have XS as a prefix
00855     char *tempname = GetTempFileName(); //_ttempnam("C:\temp", "XS");
00856     if (tempname == NULL)
00857     {
00858         ERROR3("Couldn't get a temp filename");
00859         return(FALSE);
00860     }
00861 
00862     // ---
00863     // Get the header data out of the clipboard, and copy the referenced metafile to disc
00864     METAFILEPICT *Info = (METAFILEPICT *) GlobalLock(ClipboardData);
00865 
00866     if (Info == NULL)
00867     {
00868         RemoveTempFile();
00869         return(FALSE);
00870     }
00871 
00872     HMETAFILE hCopy = CopyMetaFile(Info->hMF, tempname);
00873 
00874     GlobalUnlock(ClipboardData);
00875 
00876     if (hCopy != NULL)
00877     {
00878         ok = ImportFromTempFile(tempname, Caller, Dest);
00879         DeleteMetaFile(hCopy);
00880     }
00881 
00882     RemoveTempFile();
00883 
00884     return(ok);
00885 }
00886 
00887 
00888         
00889 /********************************************************************************************
00890 
00891 >   virtual BOOL MetaFileClipMap::HandleExport(Operation *Caller,
00892                                                 InternalClipboard *Source)
00893 
00894     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00895     Created:    20/4/95
00896 
00897     Inputs:     Caller - the operation within which this method is being called
00898                 Source - the internal clipboard (document) to be exported
00899 
00900     Returns:    NULL (if it failed), or a windows handle of the data to be placed on
00901                 the clipboard.
00902 
00903     Purpose:    Invokes this mapping for exporting
00904                 This takes the document tree of Source, and exports it to the external
00905                 (windows) clipboard. Usually this just involves calling Filter::DoExport
00906                 for the parent filter, and then returning the handle to the global memory
00907                 block to be placed onto the external clipboard.
00908 
00909     Notes:      The returned handle should be the thing you'd pass to SetClipboardData
00910                 if you were dealing with it directly. You must adhere to all the Windows
00911                 rules for this - i.e. a global data block, unlocked, etc etc.
00912 
00913 ********************************************************************************************/
00914 HANDLE MetaFileClipMap::HandleExport(Operation *Caller, InternalClipboard *Source)
00915 {
00916 #if (_OLE_VER >= 0x200)
00917     
00918     // Check if we need to allocate some memory.
00919     HANDLE hGlobalMem;
00920     if ((hGlobalMem = m_hMem) != 0)
00921     {
00922         // We have some already.  Is it big enough?
00923         if (m_cbMemSize < sizeof(METAFILEPICT)) return 0;
00924     }
00925     else
00926     {
00927         // We must allocate some.
00928         hGlobalMem = m_hMem = GlobalAlloc(GHND, sizeof(METAFILEPICT));
00929         if (!hGlobalMem) return 0;
00930     }
00931 
00932 #else
00933 
00934     HANDLE hGlobalMem = GlobalAlloc(GHND, sizeof(METAFILEPICT));
00935     if (!hGlobalMem) return 0;
00936 
00937 #endif
00938 
00939     METAFILEPICT* Info = (METAFILEPICT*) GlobalLock(hGlobalMem);
00940 
00941     // Initialise to suitable defaults, just in case
00942     Info->mm    = MM_ANISOTROPIC;
00943     Info->xExt  = 0;
00944     Info->yExt  = 0;
00945     Info->hMF   = NULL; 
00946 
00947     // --- Now, export the source clipboard to a memory metafile
00948     // Create a dummy MemFile to keep the exporter happy
00949     char *temp[1024];
00950     CCMemFile DummyFile(temp, 1000);
00951 
00952     ((MetaFileFilter *)pFilter)->DoExport(Caller, &DummyFile, (Document *)Source, Info);
00953 
00954     if (DummyFile.isOpen()) DummyFile.close();
00955 
00956     // -- Finally, lob the metafile on the clipboard (we can forget about it now, as
00957     // it is now owned (and will be deleted) by the OS)
00958     // We must unlock the block before giving it to the clipboard
00959     GlobalUnlock(hGlobalMem);
00960     return(hGlobalMem);
00961 }
00962 
00963 
00964 
00965 /********************************************************************************************
00966 
00967 >   MetaFileFilter::MetaFileFilter()
00968 
00969     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00970     Created:    18/11/93
00971     Purpose:    MetaFile filter constructor - this initialises the default attributes.
00972 
00973 ********************************************************************************************/
00974 MetaFileFilter::MetaFileFilter()
00975 {
00976     // Set up filter descriptions.
00977     FilterName.Load(_R(IDT_METAFILE_FILTERNAME));
00978     FilterInfo.Load(_R(IDT_METAFILE_FILTERINFO));
00979     FilterID = FILTERID_METAFILE;
00980 
00981     // We can import and export metafiles
00982     Flags.CanImport = TRUE ;
00983     Flags.CanExport = TRUE;
00984 
00985     OutputFile = NULL;
00986     ExportRegion = NULL;
00987     ExportMsgID = _R(IDT_EXPORTMSG_METAFILE1);
00988 
00989     // Default values
00990     FlipYCoords = FALSE;
00991     YShift = 0;
00992     IsYExtentNegative = FALSE;
00993     Dpi = 96;
00994 
00995     // Default to Black text
00996     TextColour = DocColour(0,0,0);
00997 
00998     // Set up the font
00999     SelectedFont.lfHeight = -96;
01000     SelectedFont.lfWidth = 0;
01001     SelectedFont.lfEscapement = 0;
01002     SelectedFont.lfOrientation = 0;
01003     SelectedFont.lfWeight = 0;
01004     SelectedFont.lfItalic = FALSE;
01005     SelectedFont.lfUnderline = FALSE;
01006     SelectedFont.lfStrikeOut = FALSE;
01007     SelectedFont.lfCharSet = 0;
01008     SelectedFont.lfOutPrecision = 3;
01009     SelectedFont.lfClipPrecision = 2;
01010     SelectedFont.lfQuality = 1;
01011     SelectedFont.lfPitchAndFamily = 18;
01012     
01013     camStrcpy(SelectedFont.lfFaceName, (TCHAR *)String_64(_R(IDS_METAFILT_FONT))/*"Times New Roman"*/);
01014 
01015     // Clear out the view
01016     pMetaView = NULL;
01017 };
01018 
01019 /********************************************************************************************
01020 
01021 >   void MetaFileFilter::AddNodeToMetaFileGroup(NodeRenderableBounded *pNewNode)
01022 
01023     Author:     Jonathan_Payne (Xara Group Ltd) <camelotdev@xara.com>
01024     Created:    06/11/2000
01025     Inputs:     pNewNode
01026     Returns:    True if all is OK
01027     Purpose:    Inserts a new node into the group the meta file is being imported into
01028 
01029 ********************************************************************************************/
01030 void MetaFileFilter::AddNodeToMetaFileGroup(NodeRenderableBounded *pNewNode)
01031 {
01032     if (pLastInsertedNode)
01033         // The group we are adding to has some objects in it se we just need
01034         // to instert the new node as NEXT after pLastInsertedNode
01035         pNewNode->AttachNode(pLastInsertedNode, NEXT);
01036     else
01037         // pLastInsertedNode == 0 so this is the fist object to be inserted into the
01038         // group so the object is inserted as LASTCHILD of the group
01039         pNewNode->AttachNode(pNode, LASTCHILD);
01040 
01041     pNewNode->GetBoundingRect();
01042 
01043     // Update pLastInsertedNode pointer
01044     pLastInsertedNode = pNewNode;
01045 }
01046 
01047 /********************************************************************************************
01048 
01049 >   MetaFileFilter::~MetaFileFilter()
01050 
01051     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01052     Created:    18/11/93
01053     Purpose:    Destructor for the metafile filter.
01054                 Does nothing at present.
01055 
01056 ********************************************************************************************/
01057 MetaFileFilter::~MetaFileFilter()
01058 {
01059 }
01060 
01061 /********************************************************************************************
01062 
01063 >   BOOL MetaFileFilter::Init()
01064 
01065     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01066     Created:    18/11/93
01067     Returns:    TRUE if it worked, FLASE if it failed
01068     Purpose:    Initialise the filter.
01069 
01070 ********************************************************************************************/
01071 BOOL MetaFileFilter::Init()
01072 {
01073     // Get the OILFilter object
01074     // This is deleted in the base class destructor
01075     pOILFilter = new MetaFileOILFilter(this);
01076     if (pOILFilter==NULL)
01077         // Error state already set by new
01078         return FALSE;       
01079 
01080     MetaFile = NULL;
01081     MetaFileDC = NULL;
01082     Handles = NULL;
01083 
01084     // Register ourselves with the clipboard: We can provide import and export mappings
01085     // between internal "vector" format and windows metafiles (CF_METAFILEPICT).
01086     // Our mapping has a priority level of 100.
01087     InternalClipboardFormat Format(CLIPTYPE_VECTOR);
01088     MetaFileClipMap::CreateAndRegister(CLIPMAP_IMPORTONLY, this, Format, CF_METAFILEPICT, 100);
01089 
01090     // All ok
01091     return TRUE;
01092 }
01093 
01094 
01095 /********************************************************************************************
01096 
01097 >   virtual BOOL MetaFileFilter::IsDefaultDocRequired(const TCHAR* pcszPathName)
01098 
01099     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01100     Created:    10/10/95
01101     Inputs:     pcszPathName    pointer to the pathname to check
01102     Returns:    TRUE if the filter requires a default document, FALSE if not.
01103     Purpose:    Works out if opening a file of this type requires a default document to be
01104                 loaded. If the file format supplies the document then return FALSE otherwise
01105                 return TRUE. An example would be opening a bitmap file. This has no document
01106                 defined in the file format and so we need to laod the default document before
01107                 importing the bitmap into this file.
01108                 In this baseclass version return FALSE and hence assume that the filters that
01109                 need to will override this function to return TRUE.
01110     SeeAlso:    Filter::IsDefaultDocRequired; FilterFamily::IsDefaultDocRequired;
01111                 CCamDoc::OnOpenDocument;
01112                 FilterFamily::DoImport; Filter::DoImport; 
01113 
01114 ********************************************************************************************/
01115 BOOL MetaFileFilter::IsDefaultDocRequired(const TCHAR* pcszPathName)
01116 {
01117     // No need to check the pathname, just return TRUE as all this current filter has no
01118     // concept of page size, layout etc and hence will require the default document.
01119     return TRUE;
01120 }   
01121 
01122 /********************************************************************************************
01123 
01124 >   BOOL MetaFileFilter::PrepareToImport()
01125 
01126     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01127     Created:    22/02/94
01128     Returns:    TRUE if it succeeds, FALSE if not.
01129     Purpose:    Sets up the MetaFile filter so it can read in a metafile.
01130     Errors:     None
01131 
01132 ********************************************************************************************/
01133 BOOL MetaFileFilter::PrepareToImport()
01134 {
01135     // Not attached to a metafile
01136     ENSURE(MetaFile == NULL, "PrepareToImport: still attached to a metafile!");
01137     MetaFile = NULL;
01138     ENSURE(MetaFileDC == NULL, "PrepareToImport: still attached to a metafile DC!");
01139     MetaFileDC = NULL;
01140 
01141     // Get some attributes
01142     if (!SetUpCurrentAttrs())
01143         return FALSE;
01144 
01145     // Get a handle table
01146     ENSURE(Handles == NULL, "PrepareToImport: still got a handle table!");
01147     Handles = new HandleTable(this);
01148     if (Handles==NULL)
01149         // Error state already set by new
01150         return FALSE;
01151 
01152     // For progress cursor update.
01153     FileSize = 0;
01154     BytesRead = 0;
01155 
01156     // Prepare pseudo-graphics mode
01157     CurrentMappingMode = MM_TEXT;
01158     MetaFileOrigin.x = 0;
01159     MetaFileOrigin.y = 0;
01160 
01161     // Default to Black text
01162     TextColour = DocColour(0,0,0);
01163 
01164     return TRUE;
01165 }
01166 
01167 /********************************************************************************************
01168 
01169 >   void MetaFileFilter::CleanUpAfterImport()
01170 
01171     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01172     Created:    24/02/94
01173     Purpose:    Delete dynamic objects used in the import process.
01174     SeeAlso:    MetaFileFilter::PrepareToImport; MetaFileFilter::DoImport
01175 
01176 ********************************************************************************************/
01177 void MetaFileFilter::CleanUpAfterImport()
01178 {
01179     DeleteCurrentAttrs();
01180 
01181     // Release our handle to the metafile
01182     if (MetaFile != NULL)
01183     {
01184         if (!::DeleteMetaFile(MetaFile))
01185             ENSURE(FALSE, "Error occured while closing metafile");
01186         MetaFile = NULL;
01187     }
01188 
01189     // Release our handle to the metafile's DC
01190     if (MetaFileDC != NULL)
01191     {
01192         if (!::CloseMetaFile(MetaFileDC))
01193         {
01194             ENSURE(FALSE, "Error occured while closing metafile");
01195         }
01196         MetaFileDC = NULL;
01197     }
01198 
01199     // Get rid of our handle table
01200     delete Handles;
01201     Handles = NULL;
01202 }
01203 
01204 
01205 /********************************************************************************************
01206 
01207 >   INT32 MetaFileFilter::DecodeMetaFile(HDC hdc, HANDLETABLE FAR* pHandleTable, 
01208                                    METARECORD FAR* pMetaRec, INT32 cObj, LPARAM lParam)
01209 
01210     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01211     Created:    08/03/94
01212     Inputs:     hdc - the DC of the metafile.
01213                 pHandleTable - pointer to the handle table that GDI maintains while
01214                                enumerating a metafile (NB this is not the same thing as the
01215                                Camelot 'HandleTable' class).
01216                 pMetaRec - pointer to the metafile record to be decoded.
01217                 cObj - number of objects that have handles in the handle table (ignored).
01218                 lParam - user data; actually a pointer to the relevant MetaFileFilter object.
01219     Returns:    1 => Keep enumerating the metafile
01220                 0 => An error occurred - stop enumerating the metafile now.
01221     Purpose:    Callback function for decoding metafiles.  This is called by the SDK function
01222                 EnumMetaFile, and decodes each record that it is passed into the relevant
01223                 Camelot object.
01224     Errors:     Out of memory; Syntax error/corruption in metafile (e.g. trying to select
01225                 a non-existent object).
01226     SeeAlso:    MetaFileFilter
01227 
01228 ********************************************************************************************/
01229 INT32 CALLBACK MetaFileFilter::DecodeMetaFile(HDC hdc, HANDLETABLE FAR* pHandleTable, 
01230                                        METARECORD FAR* pMetaRec, INT32 cObj, LPARAM lParam)
01231 {
01232     MetaFileFilter *Filter = (MetaFileFilter*)lParam;
01233     INT32 Result = Filter->DecodeMetafileRecord(pMetaRec);
01234 
01235     // If there was an error, return an error to the caller
01236     if (Result!=1)
01237         ERROR1(FALSE, _R(IDE_BADMETAFILE));
01238 
01239     // if there was no error, return asking for the next record
01240     return 1;
01241 }
01242 
01243 /********************************************************************************************
01244 
01245 >   BOOL MetaFileFilter::OpenAndIterateMetafile( CCLexFile* pDiskFile )
01246 
01247     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
01248     Created:    10/3/95
01249     Purpose:    Virtual fn which opens and enumerates the metafile. This can be overriden
01250                 for other metafile-based readers (e.g. AldusFormatfilter).
01251     Returns:    TRUE if OK, FALSE if not (and sets error code).
01252     SeeAlso:    MetaFileFilter::DoImport
01253 
01254 ********************************************************************************************/
01255 BOOL MetaFileFilter::OpenAndIterateMetafile(CCLexFile *pDiskFile)
01256 {
01257     // Try to open the file.
01258     if (!pDiskFile->IS_KIND_OF(CCDiskFile))
01259     {
01260         TRACEUSER( "JustinF", _T("Non-CCDiskFile in MetaFileFilter::OpenAndIterateMetafile\n"));
01261         return FALSE;
01262     }
01263 
01264     METADATA MetaData;
01265     PathName Path = ((CCDiskFile*) pDiskFile)->GetPathName();
01266     String_256 PathString = Path.GetPath();
01267     MetaFile = GetMetaFileHandle((TCHAR*) PathString, &MetaData);
01268 
01269     if (MetaFile == NULL)
01270     {
01271         // MetaFile failed to open
01272         TRACEUSER( "Jonathan", _T("Could not open metafile\n"));
01273         ERROR(_R(IDT_IMPORT_NOTFOUND), FALSE);
01274     }
01275 
01276     // Set the placeable flag so the callback knows what kind of file this is.
01277     Placeable = MetaData.Placeable;
01278 
01279     // If this is a placeable, get the size and origin of this file.
01280     if (Placeable)
01281     {
01282         // Origin is bottom left of bounding box
01283         MetaFileOrigin.x = MetaData.Header.bbox.left;
01284         MetaFileOrigin.y = MetaData.Header.bbox.bottom;
01285 
01286         // Find out the width and height of the bbox
01287         FlipYCoords = FALSE;
01288         IsYExtentNegative = FALSE;
01289 
01290         // See which way up it all is
01291         INT32 YExtent = MetaData.Header.bbox.top-MetaFileOrigin.y;
01292         if (YExtent < 0)
01293             IsYExtentNegative = TRUE;
01294 
01295         // adjust the origin if needed
01296         if (MetaFileOrigin.y > MetaData.Header.bbox.top)
01297             YShift = -YExtent;
01298 
01299         // Scaling factor is defined in units per inch
01300         // Convert to millipoints: (n / units per inch) * 72000
01301         Dpi = MetaData.Header.inch;
01302         ScaleFactor = (72000 / MetaData.Header.inch);
01303 
01304         TRACEUSER( "Jonathan", _T("Placable metafile -\n  (%ld, %ld) %ld\n"), MetaFileOrigin.x, MetaFileOrigin.y, ScaleFactor);
01305         TRACEUSER( "Jonathan", _T("Bbox (%ld, %ld)\n     (%ld, %ld)\n"), MetaData.Header.bbox.left, MetaData.Header.bbox.bottom, MetaData.Header.bbox.right, MetaData.Header.bbox.top);
01306         TRACEUSER( "Jonathan", _T("Is Negative %d\n"), IsYExtentNegative);
01307     }
01308     else
01309     {
01310         // Sensible default values for non-placeable metafiles.
01311         MetaFileOrigin.x = 0;
01312         MetaFileOrigin.y = 0;
01313         ScaleFactor = 72000 / 96;
01314         FlipYCoords = FALSE;
01315         YShift = 0;
01316         
01317         // By default windows has the 0,0 at the top left, we have it at the bottom left
01318         IsYExtentNegative = TRUE;
01319         Dpi = 96;
01320         TRACEUSER( "Jonathan", _T("Non-Placable metafile -\n  Origin (%ld, %ld) ScaleFactor %ld\n"), MetaFileOrigin.x, MetaFileOrigin.y, ScaleFactor);
01321         TRACEUSER( "Jonathan", _T("Is Negative %d\n"), IsYExtentNegative);
01322     }
01323 
01324     // Find out the size of the file, in bytes.
01325     FileSize = GetMetaFileBitsEx(MetaFile, 0, NULL);
01326     if (FileSize == 0)
01327     {
01328         if (IsUserName("Rik"))
01329             TRACE( _T("Couldn't take size of the MetaFile\n"));
01330         ERROR(_R(IDT_IMPORT_NOTFOUND), FALSE);
01331     }
01332 
01333     // Create a device context for our metafile
01334     MetaFileDC = CreateMetaFile(NULL);
01335     if (MetaFileDC == NULL)
01336     {
01337         return FALSE;
01338     }
01339 
01340     // Set the progress indicator, this next bit might take a while.
01341     String_64 ImportMessage(_R(IDT_IMPORTMSG_METAFILE));
01342     ImportMessage = GetImportProgressString(pDiskFile, _R(IDT_IMPORTMSG_METAFILE));
01343     BeginSlowJob(FileSize, TRUE, &ImportMessage);
01344 
01345     // Process the metafile by enumerating it via GDI
01346     BOOL Worked = ::EnumMetaFile(MetaFileDC, MetaFile, DecodeMetaFile, (LPARAM) this);
01347 
01348     EndSlowJob();
01349 
01350     return Worked;
01351 }
01352 
01353 /********************************************************************************************
01354 >   BOOL MetaFileFilter::DoImport(SelOperation *Op, CCLexFile* pDiskFile, 
01355                               Document *DestDoc, BOOL AutoChosen, ImportPosition *Pos,
01356                               KernelBitmap** ppImportedBitmap,DocCoord* pPosTranslate, String_256* URL)
01357     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01358     Created:    18/11/93
01359     Inputs:     Op - pointer to the operation that this read process is associated with.
01360                 pDiskFile - The file that we want to import
01361                 DestDoc - pointer to the document to insert the MetaFile data into.
01362                 AutoChosen - TRUE if the filter system selected this filter automatically,
01363                              and not the user.
01364                 Pos -
01365                 ppImportedBitmap - this is used mainly in the bitfltr.cpp for the HTML
01366                 import filter. HTMLFilter::DoImport() needs a pointer to a kernel bitmap
01367                 to set the background bitmap up into Camelot.
01368                 pPosTranslate - This is used too by the HTMLFilter in order to do a formatting.
01369                 URL - original URL of the imported file
01370     Returns:    TRUE if the read was successful, FALSE if not.
01371     Purpose:    Import the named Windows metafile into the specified document.
01372                 Currently, the data is always positioned on the first page of the first
01373                 spread in the first chapter.
01374     Errors:     Unable to open file, corrupted document tree found.
01375 ********************************************************************************************/
01376 BOOL MetaFileFilter::DoImport(SelOperation *Op, CCLexFile* pDiskFile, 
01377                               Document *DestDoc, BOOL AutoChosen, ImportPosition *pPos,
01378                               KernelBitmap** ppImportedBitmap,DocCoord* pPosTranslate, String_256* URL)
01379 {
01380     // Set up value for each import
01381     InFile = 0;
01382     
01383     // We need to know which document later on
01384     TheDocument = DestDoc;
01385 
01386     // Let's get ready
01387     if (!PrepareToImport())
01388         return FALSE;
01389 
01390     // Make sure that there is a layer to put the bitmap onto
01391     if (!MakeSureLayerExists(DestDoc))
01392         // There is no layer and one could not be made, so we will have to fail
01393         return FALSE;
01394 
01395     // Find the layer on the first page of this document...
01396     pLayer = GetActiveLayer(DestDoc);
01397     ENSURE(pLayer != NULL, "Spread has no active layer"); 
01398 
01399     NodeGroup* pGroup = new NodeGroup;
01400     if (!pGroup)
01401         return FALSE;
01402     pNode = pGroup;
01403 
01404     // Put the group in the tree
01405     AttachNodeDirection dir;
01406 
01407     Node *pInsertPoint = pLayer->FindLastChild();
01408     if (pInsertPoint)
01409     {
01410         if (pInsertPoint->IsAnInsertionNode())
01411             dir = PREV;
01412         else
01413             dir = NEXT;
01414     }
01415     else
01416     {
01417         pInsertPoint = pLayer;
01418         dir = LASTCHILD;
01419     }
01420 
01421     Op->DoInsertNewNode(pGroup,         // Node to insert
01422                         pInsertPoint,   // Context
01423                         dir,            // AttachDirection
01424                         TRUE,           // InvalidateRegion
01425                         TRUE,           // ClearSelection
01426                         TRUE,           // SelectNewObject
01427                         FALSE);         // NormaliseAttributes
01428 
01429 
01430     // Set last inserted node to zero so the next node is inserted as a child of pGroup
01431     pLastInsertedNode = 0;
01432 
01433     ImportInfo.pOp = Op;
01434 
01435     if (pPos == NULL)
01436     {       
01437         ImportInfo.Pos.pSpread = GetFirstSpread(DestDoc);
01438         DocCoord centre = ImportInfo.Pos.pSpread->FindFirstPageInSpread()->GetPageRect().Centre();
01439         ImportInfo.Pos.Position.x = centre.x;
01440         ImportInfo.Pos.Position.y = centre.y;
01441     }
01442     else
01443         ImportInfo.Pos      = *pPos;
01444 
01445     // now read the file etc using virtual function so does different things on different
01446     // sub-classes
01447     AllUnderstood = TRUE;
01448     BOOL Worked = OpenAndIterateMetafile( pDiskFile );
01449 
01450     CleanUpAfterImport();
01451 
01452     if (InFile)
01453     {
01454         _lclose(InFile);
01455         InFile = 0;
01456     }
01457 
01458     if (!Worked)
01459     {
01460 //      pGroup->CascadeDelete();
01461 //      delete pGroup;
01462         return FALSE;
01463     }
01464 
01465     // Get the final group under the mouse cursor (or coords
01466     // set above if this is not a drag'n'drop)
01467     pGroup->InvalidateBoundingRect();
01468 
01469     DocCoord GroupCentre = pGroup->GetBoundingRect().Centre();
01470     DocCoord GroupTrans;
01471 
01472     GroupTrans.x = ImportInfo.Pos.Position.x - GroupCentre.x;
01473     GroupTrans.y = ImportInfo.Pos.Position.y - GroupCentre.y;
01474     
01475     Trans2DMatrix trans(GroupTrans.x, GroupTrans.y);
01476     pGroup->Transform(trans);
01477 
01478     pGroup->InvalidateBoundingRect();
01479     Op->DoInvalidateNodeRegion(pGroup, FALSE, FALSE, FALSE);
01480 
01481     // Post import
01482     if ((TheDocument!=NULL) && (pNode!=NULL))
01483         TheDocument->PostImport();
01484 
01485     // If it worked, but there was something we did not understand, explain to the user
01486     if ((Worked) && (!AllUnderstood))
01487     {
01488         Error::SetError(_R(IDS_MEATFILE_WARN), 0);
01489         InformWarning();
01490         Error::ClearError();
01491     }
01492 
01493     return Worked;
01494 }
01495 
01496 
01497 /********************************************************************************************
01498 
01499 >   BOOL MetaFileFilter::MetaFileHeaderIsOk(METAHEADER *pHeader)
01500 
01501     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01502     Created:    29/03/94
01503     Inputs:     pHeader - the header to check.
01504     Returns:    TRUE if the header looks ok;
01505                 FALSE if not.
01506     Purpose:    Evaluate a metafile header structure, to see if it looks like a real
01507                 metafile.  This is done as part of the auto-recognition process.
01508     SeeAlso:    MetaFileFilter::HowCompatible
01509 
01510 ********************************************************************************************/
01511 BOOL MetaFileFilter::MetaFileHeaderIsOk(METAHEADER *pHeader)
01512 {
01513     return( (pHeader->mtType == 1)              &&  // disk-based
01514 
01515             (pHeader->mtHeaderSize >= 9)        &&
01516             (pHeader->mtHeaderSize < 100)       &&  // assumes header wont get huge
01517 
01518             (pHeader->mtSize >= 9)              &&  // minimum file size
01519             (pHeader->mtSize < 0xFF000000L)     &&  // assume <24 bit file length
01520 
01521             (pHeader->mtVersion >= 0x200));         // allow Windows 2 MFs
01522 
01523 }
01524 
01525 
01526 /********************************************************************************************
01527 
01528 >   INT32 MetaFileFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, 
01529                                       UINT32 HeaderSize, UINT32 FileSize)
01530 
01531     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01532     Created:    29/03/94
01533     Inputs:     Filename - name of the file.
01534                 HeaderStart - Address of the first few bytes of the file.
01535                 HeaderSize - the number of bytes in the header pointed to by FileStart.
01536                 FileSize - the size of the whole file, in bytes.
01537     Returns:    A number between 0 and 10 - see base class version for details
01538     Purpose:    Find out how compatible a file is with this import filter, i.e. does it look
01539                 like a metafile?  It evaluates the header structure, and checks the file
01540                 extension.
01541     SeeAlso:    Filter::HowCompatible; MetaFilefilter::MetaFileHeaderIsOk
01542 
01543 ********************************************************************************************/
01544 INT32 MetaFileFilter::HowCompatible(PathName& Filename, ADDR HeaderStart, UINT32 HeaderSize,
01545                                   UINT32 FileSize)
01546 {
01547     // Check to see if this is a placeable metafile.
01548     METAFILEHEADER *pMetaFileHeader = (METAFILEHEADER *) HeaderStart;
01549 
01550     if (pMetaFileHeader->key == METAFILEHEADERKEY)
01551         // It's a metafile
01552         return 10;
01553 
01554     // Not a placeable metafile - examine header for sane METAHEADER structure.
01555     METAHEADER *pMetaHeader = (METAHEADER *) HeaderStart;
01556 
01557     if (MetaFileHeaderIsOk(pMetaHeader))
01558     {
01559         // Could be a metafile - check extension
01560         String Extension = Filename.GetType();
01561         if (_tcsicmp((TCHAR *) Extension, "wmf") == 0)
01562             // Likely to be a metafile
01563             return 9;
01564         else
01565             // Could still be a metafile, but less likely
01566             return 5;
01567     }
01568     else
01569         // We can't handle this file
01570         return 0;
01571 }
01572 
01573 
01574 /********************************************************************************************
01575 
01576 >   HMETAFILE MetaFileFilter::GetMetaFileHandle(LPSTR Filename, METADATA *pMetaData)
01577 
01578     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01579     Created:    29/03/94
01580     Inputs:     Filename - name of the file to attempt to load as a metafile.
01581     Outputs:    pMetaData - various data about the metafile, if it was loaded successfully.
01582     Returns:    Handle to the loaded metafile, or NULL if an error occured.
01583     Purpose:    Given a filename, obtain a handle to the metafile, and provide basic info
01584                 about the metafile. (Based on code written by Andy for MetaView).
01585     Errors:     Unable to open file; Unable to read enough data from file; Header looks
01586                 invalid; Out of memory.
01587     SeeAlso:    METADATA
01588 
01589 ********************************************************************************************/
01590 HMETAFILE MetaFileFilter::GetMetaFileHandle(LPSTR Filename, METADATA *pMetaData)
01591 {
01592     OFSTRUCT OpenBuf;
01593 
01594     // Try to open the file
01595     OpenBuf.cBytes = sizeof(OpenBuf);
01596     InFile = OpenFile(Filename, &OpenBuf, OF_READ);
01597 
01598     // Did it work ok?
01599     if (InFile == HFILE_ERROR)
01600         return NULL;
01601 
01602     // Read in the first dword of the file to see if this is a placeable metafile
01603     INT32 BytesRead = _lread(InFile, &pMetaData->Header, sizeof(DWORD));
01604 
01605     if (BytesRead != sizeof(DWORD))
01606     {
01607         // Unable to read from the file - return error.
01608         _lclose(InFile);
01609         InFile = 0;
01610         return NULL;
01611     }
01612 
01613     METAHEADER MetaHeader;
01614 
01615     // Is this a placeable metafile?
01616     if (pMetaData->Header.key != METAFILEHEADERKEY)
01617     {
01618 
01619         // Not placable - if it looks OK, let the system read it
01620         // Go to the start of the file, read the header in, and close the file.
01621         _llseek(InFile, 0L, 0);
01622         _lread(InFile, &MetaHeader, sizeof(MetaHeader));
01623         _lclose(InFile);
01624         InFile = 0;
01625 
01626         if (!MetaFileHeaderIsOk(&MetaHeader))
01627             // Can't handle this file - return ERROR
01628             return NULL;
01629 
01630         // Looks ok - get the system to try and read it
01631         pMetaData->Placeable = FALSE;
01632         return ::GetMetaFile(Filename);
01633     }
01634 
01635     // Read the placeable header in.
01636     BytesRead = _lread(InFile, (LPVOID) &(pMetaData->Header.hmf), sizeof(METAFILEHEADER)-sizeof(DWORD));
01637 
01638     // Did it work?
01639     if (BytesRead!=(sizeof(METAFILEHEADER)-sizeof(DWORD)))
01640     {
01641         // No - return error
01642         _lclose(InFile);
01643         InFile = 0;
01644         return NULL;
01645     }
01646 
01647     // Read standard metafile header in.
01648     BytesRead = _lread(InFile, (LPSTR) &MetaHeader, sizeof(METAHEADER));
01649 
01650     // Did it work?
01651     if (BytesRead != sizeof(METAHEADER))
01652     {
01653         // No - return error.
01654         _lclose(InFile);
01655         InFile = 0;
01656         return NULL;
01657     }
01658 
01659     // Allocate memory for the metafile bits.
01660     GLOBALHANDLE MemHandle = GlobalAlloc(GHND, (MetaHeader.mtSize * 2L));
01661 
01662     if (MemHandle == NULL)
01663     {
01664         // Didn't get the memory - return error
01665         _lclose(InFile);
01666         InFile = 0;
01667         return NULL;
01668     }
01669 
01670     // Lock the memory.
01671     LPSTR MemPtr = (LPSTR) GlobalLock(MemHandle);
01672 
01673     if (MemPtr == NULL)
01674     {
01675         // Unable to lock memory - return error
01676         GlobalFree(MemHandle);
01677         _lclose(InFile);
01678         InFile = 0;
01679         return NULL;
01680     }
01681 
01682     // Seek past the header
01683     _llseek(InFile, sizeof(METAFILEHEADER), 0);
01684 
01685     // Read metafile bits.
01686     BytesRead = _lread(InFile, MemPtr, (UINT32)(MetaHeader.mtSize * 2));
01687 
01688 
01689     // Did we read the correct number of bytes?
01690     if ((UINT32) BytesRead == (MetaHeader.mtSize * 2))
01691     {
01692         // Read the data ok - set the metafile bits.
01693         HMETAFILE MetaFileHandle;
01694         MetaFileHandle = SetMetaFileBitsEx(BytesRead, (LPBYTE) MemPtr);
01695 
01696         if (MetaFileHandle != NULL)
01697         {
01698             // At last - it's all worked; return the metafile handle
01699             pMetaData->Placeable = TRUE;
01700             return MetaFileHandle;
01701         }
01702     }
01703 
01704     // Failure - clean up and return error.
01705     GlobalUnlock(MemHandle);
01706     GlobalFree(MemHandle);
01707     _lclose(InFile);
01708     InFile = 0;
01709 
01710     return NULL;
01711 }
01712 
01713 /********************************************************************************************
01714 
01715 <   POLYPOLYGON_INFO
01716 
01717     Comment:    Used to decode metafile records when importing metafiles.
01718     SeeAlso:    MetaFileFilter; MetaFileFilter::DecodePolyPolygon
01719 
01720 ********************************************************************************************/
01721 typedef struct
01722 {
01723     INT16 PolyCount;
01724     INT16 VertCounts[1];
01725 } POLYPOLYGON_INFO16;
01726 
01727 
01728 /********************************************************************************************
01729 
01730 >   BOOL MetaFileFilter::DecodeBitBlt(METARECORD* pMetaRec)
01731 
01732     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01733     Created:    25/5/95
01734     Inputs:     pMetaRec - the metafile records that holds the info about the bitmap
01735     Returns:    TRUE if the bitmap was decoded, FALSE if there was a problem
01736     Purpose:    Decodes the bitmap from the metafile and creates a NodeBitmap in the
01737                 tree of the correct size etc.
01738 
01739 ********************************************************************************************/
01740 BOOL MetaFileFilter::DecodeBitBlt(METARECORD* pMetaRec)
01741 {
01742     TRACEUSER( "Jonathan", _T("Decoding Bit Blt\n"));
01743     AllUnderstood = FALSE;
01744     return TRUE;
01745 }
01746 
01747 
01748 /********************************************************************************************
01749 
01750 >   BOOL MetaFileFilter::DecodeStretchBlt(METARECORD* pMetaRec)
01751 
01752     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01753     Created:    25/5/95
01754     Inputs:     pMetaRec - the metafile records that holds the info about the bitmap
01755     Returns:    TRUE if the bitmap was decoded, FALSE if there was a problem
01756     Purpose:    Decodes the bitmap from the metafile and creates a NodeBitmap in the
01757                 tree of the correct size etc.
01758 
01759 ********************************************************************************************/
01760 
01761 BOOL MetaFileFilter::DecodeStretchBlt(METARECORD* pMetaRec)
01762 {
01763     TRACEUSER( "Jonathan", _T("Decoding Stretch Blt\n"));
01764     AllUnderstood = FALSE;
01765     return TRUE;
01766 }
01767 
01768 
01769 /********************************************************************************************
01770 
01771 >   BOOL MetaFileFilter::DecodeDIBToDevice(METARECORD* pMetaRec)
01772 
01773     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01774     Created:    25/5/95
01775     Inputs:     pMetaRec - the metafile records that holds the info about the bitmap
01776     Returns:    TRUE if the bitmap was decoded, FALSE if there was a problem
01777     Purpose:    Decodes the bitmap from the metafile and creates a NodeBitmap in the
01778                 tree of the correct size etc.
01779 
01780 ********************************************************************************************/
01781 BOOL MetaFileFilter::DecodeDIBToDevice(METARECORD* pMetaRec)
01782 {
01783     TRACEUSER( "Jonathan", _T("Decoding Set DIB To Device\n"));
01784     AllUnderstood = FALSE;
01785     return TRUE;
01786 }
01787 
01788 
01789 /********************************************************************************************
01790 
01791 >   BOOL MetaFileFilter::DecodeDIBBitBlt(METARECORD* pMetaRec)
01792 
01793     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01794     Created:    25/5/95
01795     Inputs:     pMetaRec - the metafile records that holds the info about the bitmap
01796     Returns:    TRUE if the bitmap was decoded, FALSE if there was a problem
01797     Purpose:    Decodes the bitmap from the metafile and creates a NodeBitmap in the
01798                 tree of the correct size etc.
01799 
01800 ********************************************************************************************/
01801 BOOL MetaFileFilter::DecodeDIBBitBlt(METARECORD* pMetaRec)
01802 {
01803     TRACEUSER( "Jonathan", _T("Decoding DIB Bit Blt\n"));
01804     AllUnderstood = FALSE;
01805     return TRUE;
01806 }
01807 
01808 
01809 /********************************************************************************************
01810 
01811 >   BOOL MetaFileFilter::DecodeDIBStretchBlt(METARECORD* pMetaRec)
01812 
01813     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01814     Created:    25/5/95
01815     Inputs:     pMetaRec - the 16bit metafile record
01816     Returns:    TRUE if all went well, FALSE if there was a problem
01817     Purpose:    Decodes the StretchBlt function in a Metafile. It builds a NodeBitmap and
01818                 adds it to the tree.
01819 
01820 ********************************************************************************************/
01821 BOOL MetaFileFilter::DecodeDIBStretchBlt(METARECORD* pRec)
01822 {
01823     TRACEUSER( "Jonathan", _T("Decoding DIBSTRETCHBLT\n"));
01824     AllUnderstood = FALSE;
01825 /*
01826     // Get the bitmap info block
01827     LPWORD pWords = (LPWORD) pRec->rdParm;
01828     
01829     // Step over the Rop field and all the src coord fields
01830     // There are 6 words worth of this in a StrecthBlt
01831     pWords+=6;
01832     
01833     // Read in all the coords for the bitmap
01834     INT16 DestYExt = (UINT16) *pWords++;
01835     INT16 DestXExt = (UINT16) *pWords++;
01836     INT16 DestY = (UINT16) *pWords++;
01837     INT16 DestX = (UINT16) *pWords++;
01838 
01839     // Get at the bitmap info structure, and the bitmap info header in that
01840     BITMAPINFO* pBmpInfo = (BITMAPINFO*) pWords;
01841     KernelBitmap* pBitmap = CreateBitmap(pBmpInfo);
01842 
01843     // There was an error, so send it up
01844     if (pBitmap==NULL)
01845         return FALSE;
01846 
01847     // First, set the rectangle to the right size for the bitmap...
01848     DocCoord Position((INT32)DestX, (INT32)DestY);
01849     DocCoord Size(Position.x + (INT32)DestXExt, Position.y + (INT32)DestYExt);
01850 
01851     // Get them in DocCoords
01852     TransformCoord(&Position);
01853     TransformCoord(&Size);
01854 
01855     // Build a rectangle
01856     DocRect BoundsRect;
01857     BoundsRect.lo.x = min(Position.x, Size.x);
01858     BoundsRect.lo.y = min(Position.y, Size.y);
01859     BoundsRect.hi.x = max(Position.x, Size.x);
01860     BoundsRect.hi.y = max(Position.y, Size.y);
01861                  Poly
01862     // Create a NodeBitmap to put it in
01863     NodeBitmap* pNodeBitmap = BuildNodeBitmap(pBitmap, BoundsRect);
01864 */
01865     // return Happy
01866     return TRUE;
01867 }
01868 
01869 
01870 /********************************************************************************************
01871 
01872 >   BOOL MetaFileFilter::DecodeStretchDIB(METARECORD* pRec)
01873 
01874     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01875     Created:    24/5/95
01876     Inputs:     pRec - the Metafile record
01877     Returns:    TRUE if it decoded the record ok, FALSE if there was a problem
01878     Purpose:    Decodes the StretchDIB record from a metafile and makes a NodeBitmap object
01879                 out of it.
01880 
01881 ********************************************************************************************/
01882 BOOL MetaFileFilter::DecodeStretchDIB(METARECORD* pRec)
01883 {
01884     TRACEUSER( "Jonathan", _T("Decoding Stretch DIB\n"));
01885 
01886     // Get the bitmap info block
01887     LPWORD pWords = (LPWORD) pRec->rdParm;
01888     
01889     // Step over the Rop field and all the src coord fields
01890     // there are 7 words worth in a StretchDIBits function
01891     pWords+=7;
01892     
01893     // Read in all the coords for the bitmap
01894     INT16 DestYExt = (UINT16) *pWords++;
01895     INT16 DestXExt = (UINT16) *pWords++;
01896     INT16 DestY = (UINT16) *pWords++;
01897     INT16 DestX = (UINT16) *pWords++;
01898 
01899     // Get at the bitmap info structure, and the bitmap info header in that
01900     BITMAPINFO* pBmpInfo = (BITMAPINFO*) pWords;
01901     KernelBitmap* pBitmap = CreateBitmap(pBmpInfo);
01902 
01903     // There was an error, so send it up
01904     if (pBitmap==NULL)
01905         return FALSE;
01906 
01907     // First, set the rectangle to the right size for the bitmap...
01908     DocCoord Position((INT32)DestX, (INT32)DestY);
01909     DocCoord Size(Position.x + (INT32)DestXExt, Position.y + (INT32)DestYExt);
01910 
01911     // Get them in DocCoords
01912     TransformCoord(&Position);
01913     TransformCoord(&Size);
01914 
01915     // Build a rectangle
01916     DocRect BoundsRect;
01917     BoundsRect.lo.x = min(Position.x, Size.x);
01918     BoundsRect.lo.y = min(Position.y, Size.y);
01919     BoundsRect.hi.x = max(Position.x, Size.x);
01920     BoundsRect.hi.y = max(Position.y, Size.y);
01921 
01922     // Create a NodeBitmap to put it in
01923     NodeBitmap* pNodeBitmap = BuildNodeBitmap(pBitmap, BoundsRect);
01924 
01925     // return Happy
01926     return TRUE;
01927 }
01928 
01929 
01930 /********************************************************************************************
01931 
01932 >   KernelBitmap* MetaFileFilter::CreateBitmap(BITMAPINFO* pBitmapStart)
01933 
01934     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01935     Created:    24/5/95
01936     Inputs:     pBitmapStart - the start of the bitmap info.
01937     Returns:    A pointer to a KernelBitmap, or NULL if one could not be created
01938     Purpose:    This function expects to find the BITMAPINFO structure at the address passed
01939                 in, immediatly followed by the Bitmap Bits (ie that actual bitmap data).
01940                 This function will try to extract the bitmap info and the bitmap bits. It
01941                 will also try to allocate memory to put a copy of the bitmap info into, and
01942                 a seperate block of memory to put the bits in. It is assumed that the pointer
01943                 passed in was found from inside a metafile so the memory is not owned by us.
01944                 We need to make a copy so that we can keep the bitmap after the metafile is
01945                 closed and thrown away by windows.
01946     Errors:     Error _R(IDS_OUT_OF_MEMORY) if there is not enough memory for the new bitmap
01947 
01948 ********************************************************************************************/
01949 KernelBitmap* MetaFileFilter::CreateBitmap(BITMAPINFO* pBitmapStart)
01950 {
01951     // Find out about the bitmap header
01952     BITMAPINFOHEADER Header = pBitmapStart->bmiHeader;
01953     LPBYTE pData = NULL;
01954 
01955     // Allocate some ram for the bitmap
01956     LPBITMAPINFO pInfo = AllocDIB(Header.biWidth, Header.biHeight, Header.biBitCount, &pData);
01957 
01958     // See if it worked
01959     if ((pInfo==NULL) || (pData==NULL))
01960         return NULL;
01961 
01962     // work out if there is a palette etc and if so, how big it is.
01963     INT32 OldPalSize = Header.biClrUsed * sizeof(RGBQUAD);
01964     INT32 NewPalSize = pInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD);
01965     ERROR3IF(OldPalSize!=NewPalSize, "Palettes are of a different size");
01966 
01967     // Work out where the real bits start
01968     LPBYTE pBitsStart = (LPBYTE) pBitmapStart;
01969     pBitsStart += sizeof(BITMAPINFOHEADER) + OldPalSize;
01970 
01971     // copy the bits into our new bitmap
01972     memcpy(pData, pBitsStart, Header.biSizeImage);
01973 
01974     // Copy the palette
01975     memcpy(pInfo->bmiColors, pBitmapStart->bmiColors, NewPalSize);
01976 
01977     // Finally create the WinBitmap with all this in it
01978     WinBitmap* pWinBitmap = new WinBitmap(pInfo, pData);
01979 
01980     // Check for out of memory
01981     if (pWinBitmap==NULL)
01982         return NULL;
01983     
01984     // Create a new KernelBitmap to put the WinBitmap into
01985     KernelBitmap* pKernelBmp = new KernelBitmap(pWinBitmap, FALSE);
01986     if (pKernelBmp==NULL)
01987     {
01988         delete pWinBitmap;
01989         return NULL;
01990     }
01991 
01992     // return the bitmap
01993     return pKernelBmp;
01994 }
01995 
01996 
01997 /********************************************************************************************
01998 
01999 >   NodeBitmap* MetaFileFilter::BuildNodeBitmap(KernelBitmap* pBitmap, const DocRect& Position)
02000 
02001     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
02002     Created:    25/5/95
02003     Inputs:     pBitmap - the bitmap to put in the NodeBitmap
02004                 Position - the rect that the bitmap will fill.
02005     Returns:    A pointer to a NodeBitmap, or NULL if there was a problem
02006     Purpose:    This function creates a NodeBitmap and attaches the Kernel bitmap to it.
02007                 When it creates the Node, it attaches it to the correct place in the sub
02008                 tree that we are building.
02009 
02010 ********************************************************************************************/
02011 NodeBitmap* MetaFileFilter::BuildNodeBitmap(KernelBitmap* pBitmap, const DocRect& Position)
02012 {
02013     // Create a NodeBitmap to put it in
02014     NodeBitmap *pNodeBitmap = new NodeBitmap;
02015 
02016     if (pNodeBitmap==NULL)
02017         return NULL;
02018 
02019     // try and set up the bitmap
02020     if (!pNodeBitmap->SetUpPath(12,12))
02021     {
02022         // Destroy the unwanted nodes
02023         pNodeBitmap->CascadeDelete();
02024         delete pNodeBitmap;
02025         return NULL;
02026     }
02027 
02028     // Make the node bitmap use the bitmap we have found
02029     pNodeBitmap->GetBitmapRef()->Attach(pBitmap, GetDocument());
02030     if (pNodeBitmap->GetBitmap() != pBitmap)
02031     {
02032         // It didn't use the bitmap we gave it, so we can delete it
02033         delete pBitmap;
02034     }
02035 
02036     // And set this in our bitmap node
02037     pNodeBitmap->CreateShape(Position);
02038 
02039     // And apply the default Bitmap attributes
02040     pNodeBitmap->ApplyDefaultBitmapAttrs(NULL);
02041 
02042     // return the bitmap we have made
02043     AddNodeToMetaFileGroup(pNodeBitmap);
02044 
02045     return pNodeBitmap;
02046 }
02047 
02048 
02049 /********************************************************************************************
02050 
02051 >   BOOL MetaFileFilter::DecodePolyPolygon(METARECORD *pRec)
02052 
02053     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02054     Created:    29/03/94
02055     Inputs:     pRec - the poly-polygon record to decode.
02056     Returns:    TRUE if the poly-polygon was decoded successfuly;
02057                 FALSE otherwise.
02058     Purpose:    Given a Metafile record for a 'poly-polygon', decode it and convert it into
02059                 a Camelot path.
02060     Errors:     Out of memory.
02061     SeeAlso:    MetaFileFilter; MetaFileFilter::DecodeMetaFile
02062 
02063 ********************************************************************************************/
02064 BOOL MetaFileFilter::DecodePolyPolygon(METARECORD *pRec)
02065 {
02066     BOOL retvalue;
02067 
02068     // Get friendly pointer to the polypolygon data.
02069     POLYPOLYGON_INFO16 *pPolyInfo = (POLYPOLYGON_INFO16 *) pRec->rdParm;
02070 
02071     // Used to read coordinates from the data structure
02072     DocCoord Coord;
02073 
02074     // Used to set the bound rectangle of the path.
02075     DocRect BoundingRect;
02076 
02077     // Find out how many polygons there are
02078     UINT32 NumPolys = (UINT32) pPolyInfo->PolyCount;
02079 
02080     // Find out how big this path is so we can give the path class a hint about how big
02081     // to make it's initial arrays.
02082  
02083     // Get pointer to start of polygon vertex counts
02084     INT16 *pVertCount = pPolyInfo->VertCounts;
02085  
02086     UINT32 NumSlots = 0;
02087  
02088     // Iterate through all the polygons to find the number of slots for this path.
02089     while (NumPolys > 0)
02090     {
02091         // Find out how many points there are
02092         NumSlots += (UINT32) *pVertCount;
02093  
02094         // Try next polygon
02095         pVertCount++;
02096         NumPolys--;
02097     }
02098 
02099     // Create a new NodePath object
02100     NodePath *pPath = new NodePath;
02101     if (pPath==NULL)
02102         return FALSE;
02103 
02104     // try and set up the path
02105     if (!pPath->SetUpPath(NumSlots))
02106     {
02107         // Couldn't initialise path - delete path (if created) and return error.
02108         // Destroy any half-created paths
02109         if (pPath != NULL)
02110             pPath->CascadeDelete();
02111         
02112         // delete the unwanted path
02113         delete pPath;
02114 
02115         // Set the error for the caller of EnumMetaFile() to report
02116         return FALSE;
02117     }
02118 
02119     // Position tag at start of path.
02120     pPath->InkPath.FindStartOfPath();
02121 
02122     // Reposition the vertex count pointer, and polygon count
02123     pVertCount = pPolyInfo->VertCounts;
02124     NumPolys = (UINT32) pPolyInfo->PolyCount;
02125 
02126     // Get pointer to start of polygon points
02127     POINT_16 *pCoord = (POINT_16 *) (pPolyInfo->VertCounts + NumPolys);
02128 
02129     // Iterate through all the polygons.
02130     while (NumPolys > 0)
02131     {
02132         // Find out how many points there are
02133         UINT32 NumPoints = (UINT32) *pVertCount;
02134 
02135         // Add the moveto to the path
02136         Coord.x = pCoord->x;
02137         Coord.y = pCoord->y;
02138         TransformCoord(&Coord);
02139         if (!pPath->InkPath.InsertMoveTo(Coord))
02140             // Not enough dynamic heap to insert the moveto command
02141             goto NoMemory;
02142 
02143         // Move past the moveto command
02144         pCoord++;
02145         NumPoints--;
02146 
02147         while (NumPoints > 0)
02148         {
02149             Coord.x = pCoord->x;
02150             Coord.y = pCoord->y;
02151             TransformCoord(&Coord);
02152             if (!pPath->InkPath.InsertLineTo(Coord))
02153                 // Not enough dynamic heap to insert the moveto command
02154                 goto NoMemory;
02155 
02156             // Try next coordinate
02157             pCoord++;
02158             NumPoints--;
02159         }
02160 
02161         // Try next polygon
02162         pVertCount++;
02163         NumPolys--;
02164     }
02165 
02166     // Remember current point
02167     pCoord--;
02168     CurrentPoint.x = pCoord->x;
02169     CurrentPoint.y = pCoord->y;
02170 
02171     // Terminate path properly.
02172     if (!pPath->InkPath.CloseSubPath())
02173         // Not enough dynamic heap to insert the closepath command
02174         goto NoMemory;
02175 
02176     // Make sure that we have a vald path here...
02177     BOOL ChangesMade;
02178     if (!pPath->InkPath.EnsureValid(&ChangesMade))
02179     {
02180         // We could not fix this path, so scrap it
02181         TRACE( _T("dpp Found a path that was so badly damaged we had to throw it away\n"));
02182         Error::ClearError();
02183 
02184         // Destroy the path
02185         if (pPath != NULL)
02186             pPath->CascadeDelete();
02187 
02188         // delete the unwanted path
02189         delete pPath;
02190 
02191         // and return without error
02192         return TRUE;
02193     }
02194 
02195     #ifdef _DEBUG
02196         // See if we had to make any changes to the path
02197         if (ChangesMade)
02198         {
02199             // yep, we sure did - tell Rik all about it
02200             TRACE( _T("We had to change this path as it was corrupt\n"));
02201         }
02202     #endif
02203 
02204     // Find out what fill colour we have (safe to do this as we only have flat fills
02205     // in metafiles), and use this to set the 'filled' flag on the path.
02206     FlatFillAttribute *pAttr;
02207     pAttr = (FlatFillAttribute *) CurrentAttrs[ATTR_FILLGEOMETRY].pAttr;
02208     ENSURE(pAttr->IsKindOf(CC_RUNTIME_CLASS(FlatFillAttribute)),
02209             "Bad fill type in metafile filter");
02210 
02211     pPath->InkPath.IsFilled = !(pAttr->Colour.IsTransparent());
02212 
02213     // Add attributes
02214     retvalue = AddAttributes(pPath);
02215 
02216     AddNodeToMetaFileGroup(pPath);
02217 
02218     return retvalue;
02219 
02220 NoMemory:
02221     // Error - Out of memory while reading metafile
02222     
02223     // Destroy any half-created paths
02224     if (pPath != NULL)
02225         pPath->CascadeDelete();
02226         
02227     // delete the unwanted path
02228     delete pPath;
02229 
02230     // Set the error for the caller of EnumMetaFile() to report
02231     return FALSE;
02232 }
02233 
02234 /********************************************************************************************
02235 
02236 >   BOOL MetaFileFilter::DecodePolygon(METARECORD *pRec, BOOL FillPolygon)
02237 
02238     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02239     Created:    29/03/94
02240     Inputs:     pRec - the polygon record to decode.
02241                 FillPolygon - TRUE if the polygon should be filled with the current fill
02242                 colour, FALSE if it should be just an outline
02243     Returns:    TRUE if the polygon was decoded successfuly;
02244                 FALSE otherwise.
02245     Purpose:    Given a Metafile record for a polygon, decode it and convert it into
02246                 a Camelot path. This function is used to decode the Polygon and PolyLine
02247                 records in a metafile. The only difference between the two is that polygons
02248                 are filled and polylines are not, hence the FillPolygon flag that gets passed
02249                 in
02250     Errors:     Out of memory.
02251     SeeAlso:    MetaFileFilter; MetaFileFilter::DecodeMetaFile
02252 
02253 ********************************************************************************************/
02254 
02255 BOOL MetaFileFilter::DecodePolygon(METARECORD *pRec, BOOL FillPolygon)
02256 {
02257     DocRect BoundingRect;
02258     BOOL retvalue;
02259 
02260     // Get pointer to the polygon structure
02261     INT16 *pNumPoints;
02262     pNumPoints = (INT16 *) (pRec->rdParm);
02263 
02264     // Find out how many points there are
02265     UINT32 NumPoints;
02266     NumPoints = (UINT32) *pNumPoints;
02267 
02268     // Ignore anything with less than 2 points
02269     if (NumPoints < 2)
02270         return TRUE;
02271 
02272     // Create a new NodePath pbject
02273     NodePath *pPath = new NodePath;
02274     if (pPath==NULL)
02275         return FALSE;
02276 
02277     // Try and set it up
02278     if (!pPath->SetUpPath(NumPoints))
02279     {
02280         // Couldn't initialise path - delete path (if created) and return error.
02281         // Destroy any half-created paths
02282         if (pPath != NULL)
02283             pPath->CascadeDelete();
02284         
02285         // delete the unwanted path
02286         delete pPath;
02287 
02288         // Set the error for the caller of EnumMetaFile() to report
02289         return FALSE;
02290     }
02291 
02292     // Position tag at start of path.
02293     pPath->InkPath.FindStartOfPath();
02294 
02295     // Get pointer to the first coord
02296     POINT_16 *pCoord = (POINT_16 *) (pNumPoints + 1);
02297                 
02298     // Add the moveto to the path
02299     DocCoord Coord;
02300     Coord.x = pCoord->x;
02301     Coord.y = pCoord->y;
02302     TransformCoord(&Coord);
02303     if (!pPath->InkPath.InsertMoveTo(Coord))
02304         // Not enough dynamic heap to insert the moveto command
02305         goto NoMemory;
02306 
02307     // Move past the moveto command
02308     pCoord++;
02309     NumPoints--;
02310 
02311     while (NumPoints > 0)
02312     {
02313         Coord.x = pCoord->x;
02314         Coord.y = pCoord->y;
02315         TransformCoord(&Coord);
02316         if (!pPath->InkPath.InsertLineTo(Coord))
02317             // Not enough dynamic heap to insert the moveto command
02318             goto NoMemory;
02319 
02320         // Try next coordinate
02321         pCoord++;
02322         NumPoints--;
02323     }
02324 
02325     // Remember current point
02326     pCoord--;
02327     CurrentPoint.x = pCoord->x;
02328     CurrentPoint.y = pCoord->y;
02329 
02330     // Terminate path properly.
02331     if ((FillPolygon) && (!pPath->InkPath.CloseSubPath()))
02332         // Not enough dynamic heap to insert the closepath command
02333         goto NoMemory;
02334 
02335     // Make sure that we have a vald path here...
02336     BOOL ChangesMade;
02337     if (!pPath->InkPath.EnsureValid(&ChangesMade))
02338     {
02339         // We could not fix this path, so scrap it
02340         TRACE( _T("dp Found a path that was so badly damaged we had to throw it away\n"));
02341         Error::ClearError();
02342 
02343         // Destroy the path
02344         if (pPath != NULL)
02345             pPath->CascadeDelete();
02346 
02347         // delete the unwanted path
02348         delete pPath;
02349 
02350         // and return without error
02351         return TRUE;
02352     }
02353 
02354     #ifdef _DEBUG
02355         // See if we had to make any changes to the path
02356         if (ChangesMade)
02357         {
02358             // yep, we sure did - tell Rik all about it
02359             TRACE( _T("We had to change this path as it was corrupt\n"));
02360         }
02361     #endif
02362 
02363     if (FillPolygon)
02364     {
02365         // Find out what fill colour we have (safe to do this as we only have flat fills
02366         // in metafiles), and use this to set the 'filled' flag on the path.
02367         FlatFillAttribute *pAttr;
02368         pAttr = (FlatFillAttribute *) CurrentAttrs[ATTR_FILLGEOMETRY].pAttr;
02369         ENSURE(pAttr->IsKindOf(CC_RUNTIME_CLASS(FlatFillAttribute)),
02370                 "Bad fill type in metafile filter");
02371 
02372         pPath->InkPath.IsFilled = !(pAttr->Colour.IsTransparent());
02373     }
02374     else
02375     {
02376         // Make sure that the path is not filled
02377         pPath->InkPath.IsFilled = FALSE;
02378     }
02379 
02380     // Add attributes
02381     retvalue = AddAttributes(pPath);
02382 
02383     AddNodeToMetaFileGroup(pPath);
02384 
02385     return retvalue;
02386         
02387 NoMemory:
02388     // Error - Out of memory while decoding polygon
02389     
02390     // Destroy any half-created paths
02391     if (pPath != NULL)
02392         pPath->CascadeDelete();
02393         
02394     // delete the unwanted path
02395     delete pPath;
02396 
02397     // Set the error for the caller of EnumMetaFile() to report
02398     return FALSE;
02399 }
02400 
02401 
02402 
02403 /********************************************************************************************
02404 
02405 >   BOOL MetaFileFilter::DecodeLineTo(METARECORD* pMetaRec)
02406 
02407     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
02408     Created:    19/9/95
02409     Inputs:     pMetaRec - the metafile record
02410     Returns:    TRUE if it decoded the LineTo ok, FALSE if not
02411     Purpose:    Decodes the metafile LineTo function and updates the current position
02412 
02413 ********************************************************************************************/
02414 
02415 BOOL MetaFileFilter::DecodeLineTo(METARECORD* pMetaRec)
02416 {
02417     // The current position should hold the coord for the last point drawn (eg, after a
02418     // moveto or a previous line to.
02419 
02420     // Create a new NodePath object to put the line it
02421     NodePath *pPath = new NodePath;
02422     if (pPath==NULL)
02423         return FALSE;
02424 
02425     // Try and set up the path
02426     if (!pPath->SetUpPath(2))
02427     {
02428         // Couldn't initialise path - delete path (if created) and return error.
02429         pPath->CascadeDelete();
02430         delete pPath;
02431         return FALSE;
02432     }
02433 
02434     // Position tag at start of path.
02435     pPath->InkPath.FindStartOfPath();
02436     pPath->InkPath.IsFilled = FALSE;
02437 
02438     // Insert a move to to the current point
02439     if (!pPath->InkPath.InsertMoveTo(CurrentPoint))
02440     {
02441         // Clean it up
02442         pPath->CascadeDelete();
02443         delete pPath;
02444         return FALSE;
02445     }
02446 
02447     // Decode the coord for the line to and update the current point
02448     CurrentPoint.y = (INT16) pMetaRec->rdParm[0];
02449     CurrentPoint.x = (INT16) pMetaRec->rdParm[1];
02450     TransformCoord(&CurrentPoint);
02451 
02452     // Insert a lineto to the new current point
02453     if (!pPath->InkPath.InsertLineTo(CurrentPoint))
02454     {
02455         // Clean it up
02456         pPath->CascadeDelete();
02457         delete pPath;
02458         return FALSE;
02459     }
02460 
02461     // Make sure that we have a vald path here...
02462     BOOL ChangesMade;
02463     if (!pPath->InkPath.EnsureValid(&ChangesMade))
02464     {
02465         // We could not fix this path, so scrap it
02466         TRACE( _T("dl Found a path that was so badly damaged we had to throw it away\n"));
02467         Error::ClearError();
02468         pPath->CascadeDelete();
02469         delete pPath;
02470         
02471         // This path had nothing useful in it, so just return
02472         return TRUE;
02473     }
02474 
02475     #ifdef _DEBUG
02476         // See if we had to make any changes to the path
02477         if (ChangesMade)
02478         {
02479             // yep, we sure did - tell Rik all about it
02480             TRACE( _T("We had to change this path as it was corrupt\n"));
02481         }
02482     #endif
02483 
02484     // Add attributes
02485     BOOL retvalue = AddAttributes(pPath);
02486 
02487     AddNodeToMetaFileGroup(pPath);
02488 
02489     return retvalue;
02490 }
02491 
02492 
02493 /********************************************************************************************
02494 
02495 >   BOOL MetaFileFilter::DecodeEllipse(METARECORD* pMetaRec)
02496 
02497     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
02498     Created:    29/5/95
02499     Inputs:     pMetaRec - the metafile record
02500     Returns:    TRUE if it decoded the ellipse ok, FALSE if not
02501     Purpose:    Decodes the metafile ellipse function.
02502 
02503 ********************************************************************************************/
02504 
02505 BOOL MetaFileFilter::DecodeEllipse(METARECORD* pMetaRec)
02506 {
02507     TRACEUSER( "Jonathan", _T("Decoding Ellipse\n"));
02508 
02509     // Create a new NodePath pbject
02510     NodeEllipse *pElip = new NodeEllipse;
02511     if (pElip==NULL)
02512         return FALSE;
02513 
02514     // try and set up the ellipse
02515     if (!pElip->SetUpPath(12,12))
02516     {
02517         // Couldn't initialise path - delete path (if created) and return error.
02518         pElip->CascadeDelete();
02519         delete pElip;
02520         return FALSE;
02521     }
02522 
02523     // Get pointer to the first coord
02524     INT16 *pCoord = (INT16 *) (pMetaRec->rdParm);
02525                 
02526     // Add the moveto to the path
02527     DocCoord TopRight((INT32) pCoord[1], (INT32) pCoord[2]);
02528     DocCoord BotLeft((INT32) pCoord[3], (INT32) pCoord[0]);
02529     TransformCoord(&TopRight);
02530     TransformCoord(&BotLeft);
02531 
02532     DocRect Rect(min(TopRight.x, BotLeft.x),
02533                  min(TopRight.y, BotLeft.y),
02534                  max(TopRight.x, BotLeft.x),
02535                  max(TopRight.y, BotLeft.y));
02536 
02537     // Create the ellipse
02538     pElip->CreateShape(Rect);
02539     pElip->InkPath.IsFilled = TRUE;
02540 
02541     // Add attributes
02542     BOOL retvalue = AddAttributes(pElip);
02543 
02544     AddNodeToMetaFileGroup(pElip);
02545 
02546     return retvalue;
02547 }
02548 
02549 
02550 /********************************************************************************************
02551 
02552 >   BOOL MetaFileFilter::DecodeRectangle(METARECORD* pMetaRec)
02553 
02554     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
02555     Created:    29/5/95
02556     Inputs:     pMetaRec - The metafile record
02557     Returns:    TRUE if we decoded it ok, FALSE if there was a problem
02558     Purpose:    Decodes the metafile rectangle command. We insert a Path into the tree of
02559                 the correct size.
02560 
02561 ********************************************************************************************/
02562 
02563 BOOL MetaFileFilter::DecodeRectangle(METARECORD* pMetaRec)
02564 {
02565     BOOL retvalue;
02566     TRACEUSER( "Jonathan", _T("Decoding Rectangle\n"));
02567 
02568     // Create a new NodePath pbject
02569     NodePath *pPath = new NodePath;
02570     if (pPath==NULL)
02571         return FALSE;
02572 
02573     // try and set up the path
02574     if (!pPath->SetUpPath(12,12))
02575     {
02576         // Destroy any half-created paths
02577         if (pPath != NULL)
02578             pPath->CascadeDelete();
02579         
02580         // delete the unwanted path
02581         delete pPath;
02582 
02583         // Set the error for the caller of EnumMetaFile() to report
02584         return FALSE;
02585     }
02586 
02587     // Position tag at start of path.
02588     pPath->InkPath.FindStartOfPath();
02589 
02590     // Get pointer to the first coord
02591     INT16 *pCoord = (INT16 *) (pMetaRec->rdParm);
02592                 
02593     // Add the moveto to the path
02594     DocCoord TopRight((INT32) pCoord[1], (INT32) pCoord[2]);
02595     DocCoord BotLeft((INT32) pCoord[3], (INT32) pCoord[0]);
02596     TransformCoord(&TopRight);
02597     TransformCoord(&BotLeft);
02598 
02599     DocRect Rect(min(TopRight.x, BotLeft.x),
02600                  min(TopRight.y, BotLeft.y),
02601                  max(TopRight.x, BotLeft.x),
02602                  max(TopRight.y, BotLeft.y));
02603 
02604     // Insert the move to
02605     DocCoord Coord;
02606     Coord.x = Rect.lo.x;
02607     Coord.y = Rect.lo.y;
02608     if (!pPath->InkPath.InsertMoveTo(Coord))
02609         // Not enough dynamic heap to insert the moveto command
02610         goto NoMemory;
02611 
02612     // Insert each of the line sections
02613     Coord.y = Rect.hi.y;
02614     if (!pPath->InkPath.InsertLineTo(Coord))
02615         // Not enough dynamic heap to insert the moveto command
02616         goto NoMemory;
02617 
02618     Coord.x = Rect.hi.x;
02619     if (!pPath->InkPath.InsertLineTo(Coord))
02620         // Not enough dynamic heap to insert the moveto command
02621         goto NoMemory;
02622 
02623     Coord.y = Rect.lo.y;
02624     if (!pPath->InkPath.InsertLineTo(Coord))
02625         // Not enough dynamic heap to insert the moveto command
02626         goto NoMemory;
02627 
02628     Coord.x = Rect.lo.x;
02629     if (!pPath->InkPath.InsertLineTo(Coord))
02630         // Not enough dynamic heap to insert the moveto command
02631         goto NoMemory;
02632 
02633     // Terminate path properly.
02634     if (!pPath->InkPath.CloseSubPath())
02635         // Not enough dynamic heap to insert the closepath command
02636         goto NoMemory;
02637 
02638     // Make sure that we have a vald path here...
02639     BOOL ChangesMade;
02640     if (!pPath->InkPath.EnsureValid(&ChangesMade))
02641     {
02642         // We could not fix this path, so scrap it
02643         TRACE( _T("Found a path that was so badly damaged we had to throw it away\n"));
02644         Error::ClearError();
02645 
02646         // Destroy the path
02647         if (pPath != NULL)
02648             pPath->CascadeDelete();
02649 
02650         // delete the unwanted path
02651         delete pPath;
02652 
02653         // and return without error
02654         return TRUE;
02655     }
02656 
02657     #ifdef _DEBUG
02658         // See if we had to make any changes to the path
02659         if (ChangesMade)
02660         {
02661             // yep, we sure did - tell Rik all about it
02662             TRACE( _T("We had to change this path as it was corrupt\n"));
02663         }
02664     #endif
02665 
02666     // Make sure that the path is not filled
02667     pPath->InkPath.IsFilled = TRUE;
02668 
02669     // Add attributes
02670     retvalue = AddAttributes(pPath);
02671 
02672     AddNodeToMetaFileGroup(pPath);
02673 
02674     return retvalue;
02675 
02676 NoMemory:
02677     // Error - Out of memory while decoding polygon
02678     // Destroy any half-created paths
02679     if (pPath != NULL)
02680         pPath->CascadeDelete();
02681 
02682     // delete the unwanted path
02683     delete pPath;
02684         
02685     // Set the error for the caller of EnumMetaFile() to report
02686     return FALSE;
02687 }
02688 
02689 /********************************************************************************************
02690 
02691 >   BOOL MetaFileFilter::DecodeTextStory(METARECORD* pMetaRec)
02692 
02693     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
02694     Created:    26/5/95
02695     Inputs:     pMetaRec - the record to decode
02696     Returns:    TRUE if it worked, FALSE if there was a problem
02697     Purpose:    Decodes the TextOut function and makes a text story.
02698 
02699 ********************************************************************************************/
02700 
02701 BOOL MetaFileFilter::DecodeTextStory(METARECORD* pMetaRec)
02702 {
02703     // Get the bitmap info block
02704     LPWORD pWords = (LPWORD) pMetaRec->rdParm;
02705     
02706     // Read in the number of chars in the string
02707     INT16 Count = (UINT16) *pWords++;
02708 
02709     // Get a string
02710     char* pString = new char[Count+1];
02711     if (pString==NULL)
02712         return FALSE;
02713     
02714     // Copy the chars into our new string
02715     camStrncpy(pString, (char*)pWords, Count);
02716     pString[Count] = 0;
02717     TRACE( _T("- %s\n"), pString);
02718 
02719     // Find the coords
02720     while (Count>0)
02721     {
02722         pWords++;
02723         Count-=2;
02724     }
02725 
02726     // Get a coord to house the string
02727     DocCoord Position(0,0);
02728 
02729     // Get the coordinates
02730     Position.y = (INT16) *pWords++;
02731     Position.x = (INT16) *pWords++;
02732 
02733     // transform them
02734     TransformCoord(&Position);
02735 
02736     // Build the text story
02737     TRACEUSER( "Jonathan", _T("Text Story : %s\n"), pString);
02738     TextStory* pNewStory = TextStory::CreateFromChars(Position, pString, NULL, GetDocument(),
02739                                                       &SelectedFont, FALSE, &TextColour);
02740     // Clean up the string
02741     delete pString;
02742 
02743     // See if we have a new text story
02744     if (pNewStory==NULL)
02745         return FALSE;
02746 
02747     // Yes, put it in the tree
02748     AddNodeToMetaFileGroup(pNewStory);
02749 
02750     // Return
02751     return TRUE;
02752 }
02753 
02754 
02755 
02756 /********************************************************************************************
02757 
02758 >   BOOL MetaFileFilter::DecodeExtTextStory(METARECORD* pMetaRec)
02759 
02760     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
02761     Created:    3/7/95
02762     Inputs:     pMetaRec - the metafile record for the ExtTextOut
02763     Returns:    TRUE if all went well, FALSE if there was a problem
02764     Purpose:    Decodes the ExtTextOut function.
02765 
02766 ********************************************************************************************/
02767 
02768 BOOL MetaFileFilter::DecodeExtTextStory(METARECORD* pMetaRec)
02769 {
02770     // Get the info block
02771     LPWORD pWords = (LPWORD) pMetaRec->rdParm;
02772     
02773     // Get a coord to house the string
02774     DocCoord Position(0,0);
02775 
02776     // Get the coordinates
02777     Position.y = (INT16) *pWords++;
02778     Position.y -= SelectedFont.lfHeight;
02779     Position.x = (INT16) *pWords++;
02780 
02781     // transform the Coord
02782     TransformCoord(&Position);
02783 
02784     // Read in the number of chars in the string
02785     INT16 Count = (UINT16) *pWords++;
02786 
02787     // Read in the options flag
02788     INT16 Option = (UINT16) *pWords++;
02789     if (Option!=0)
02790     {
02791         // Read in the rectangle if its there
02792         pWords++;       // left
02793         pWords++;       // top
02794         pWords++;       // right
02795         pWords++;       // bottom
02796     }
02797 
02798     // Get a string
02799     char* pString = new char[Count+1];
02800     if (pString==NULL)
02801         return FALSE;
02802     
02803     // Copy the chars into our new string
02804     camStrncpy(pString, (char*)pWords, Count);
02805     pString[Count] = 0;
02806     TRACE( _T("%s\n"), pString);
02807 
02808     // Find the coords
02809     while (Count>0)
02810     {
02811         pWords++;
02812         Count-=2;
02813     }
02814 
02815     // Build the text story
02816     TextStory* pNewStory = TextStory::CreateFromChars(Position, pString, NULL, GetDocument(),
02817                                                       &SelectedFont, FALSE, &TextColour);
02818     // Clean up the string
02819     delete pString;
02820 
02821     // See if we have a new text story
02822     if (pNewStory==NULL)
02823         return FALSE;
02824 
02825     // Yes, put it in the tree
02826     AddNodeToMetaFileGroup(pNewStory);
02827 
02828     // Return
02829     return TRUE;
02830 }
02831 
02832 
02833 
02834 
02835 /********************************************************************************************
02836 
02837 >   void MetaFileFilter::SetLogicalFont(LOGFONT* pNewFont)
02838 
02839     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
02840     Created:    26/5/95
02841     Inputs:     pNewFont - the details about the newly selected font
02842     Purpose:    Makes a note of the selected font ready for when it is used.
02843 
02844 ********************************************************************************************/
02845 
02846 void MetaFileFilter::SetLogicalFont(LOGFONT_16* pNewFont)
02847 {
02848     // record the font
02849     // Copy the values from the 16 bit version to the 32 bit version
02850     SelectedFont.lfHeight = pNewFont->lfHeight;
02851     SelectedFont.lfWidth = pNewFont->lfWidth;
02852     SelectedFont.lfEscapement = pNewFont->lfEscapement;
02853     SelectedFont.lfOrientation = pNewFont->lfOrientation;
02854     SelectedFont.lfWeight = pNewFont->lfWeight;
02855     SelectedFont.lfItalic = pNewFont->lfItalic;
02856     SelectedFont.lfUnderline = pNewFont->lfUnderline;
02857     SelectedFont.lfStrikeOut = pNewFont->lfStrikeOut;
02858     SelectedFont.lfCharSet = pNewFont->lfCharSet;
02859     SelectedFont.lfOutPrecision = pNewFont->lfOutPrecision;
02860     SelectedFont.lfClipPrecision = pNewFont->lfClipPrecision;
02861     SelectedFont.lfQuality = pNewFont->lfQuality;
02862     SelectedFont.lfPitchAndFamily = pNewFont->lfPitchAndFamily;
02863     camStrcpy(SelectedFont.lfFaceName, pNewFont->lfFaceName);
02864 
02865     // Scale the text size according to the current mapping mode.
02866     switch (CurrentMappingMode)
02867     {
02868         case MM_TEXT:
02869             // Scale is in pixels
02870             SelectedFont.lfHeight = (SelectedFont.lfHeight * 96) / Dpi;
02871             SelectedFont.lfWidth = (SelectedFont.lfWidth * 96) / Dpi;
02872             break;
02873 
02874         case MM_LOMETRIC:
02875             // Scale of 0.1mm per unit
02876             // Convert to 96 dpi
02877             SelectedFont.lfHeight = (SelectedFont.lfHeight * 96) / 254;
02878             SelectedFont.lfWidth = (SelectedFont.lfWidth * 96) / 254;
02879             break;
02880 
02881         case MM_HIMETRIC:
02882             // Scale of 0.01mm per unit
02883             // Convert to millipoints: n * (72000 / (100 * 25.4))
02884             SelectedFont.lfHeight = (SelectedFont.lfHeight * 96) / 2540;
02885             SelectedFont.lfWidth = (SelectedFont.lfWidth * 96) / 2540;
02886             break;
02887 
02888         case MM_LOENGLISH:
02889             // Scale of 0.01 inches per unit
02890             // Convert to millipoints: (n / 100) * 72000
02891             SelectedFont.lfHeight = (SelectedFont.lfHeight * 96) / 100;
02892             SelectedFont.lfWidth = (SelectedFont.lfWidth * 96) / 100;
02893             break;
02894 
02895         case MM_HIENGLISH:
02896             // Scale of 0.001 inches per unit
02897             // Convert to millipoints: (n / 1000) * 72000
02898             SelectedFont.lfHeight = (SelectedFont.lfHeight * 96) / 1000;
02899             SelectedFont.lfWidth = (SelectedFont.lfWidth * 96) / 1000;
02900             break;
02901 
02902         case MM_TWIPS:
02903             // Scale of 1/1440th of an inch per unit
02904             // Convert to millipoints: (n / 1440) * 72000
02905             SelectedFont.lfHeight = (SelectedFont.lfHeight * 96) / 1440;
02906             SelectedFont.lfWidth = (SelectedFont.lfWidth * 96) / 1440;
02907             break;
02908 
02909         default:
02910             SelectedFont.lfHeight = (SelectedFont.lfHeight * 96) / Dpi;
02911             SelectedFont.lfWidth = (SelectedFont.lfWidth * 96) / Dpi;
02912             break;
02913     }
02914 }
02915 
02916 
02917 /********************************************************************************************
02918 
02919 >   INT32 MetaFileFilter::DecodeMetafileRecord( METARECORD FAR* pMetaRec )
02920 
02921     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02922     Created:    08/03/94
02923     Inputs:
02924                 pMetaRec - pointer to the metafile record to be decoded.
02925     Returns:    1 => Keep enumerating the metafile
02926                 0 => An error occurred - stop enumerating the metafile now.
02927     Purpose:    Callback function for decoding metafiles.  This is called indirectly by the SDK function
02928                 EnumMetaFile, and decodes each record that it is passed into the relevant
02929                 Camelot object.
02930     Errors:     Out of memory; Syntax error/corruption in metafile (e.g. trying to select
02931                 a non-existent object).
02932     SeeAlso:    MetaFileFilter
02933 
02934 ********************************************************************************************/
02935 
02936 INT32 MetaFileFilter::DecodeMetafileRecord( METARECORD FAR* pMetaRec )
02937 {
02938     NodePath    *pPath = NULL;
02939     DocCoord     Coord;
02940     LOGPEN_16   *pPen;
02941     LOGBRUSH_16 *pBrush;
02942     DocRect      BoundingRect;
02943     LOGFONT_16*  pFont;
02944     LOGPALETTE_16* pPalette;
02945 
02946     // The rdSize field is the size of this record in words.
02947     BytesRead += pMetaRec->rdSize * 2;
02948 
02949     // Keep it less than the filesize
02950     if (BytesRead>FileSize)
02951         BytesRead = FileSize;
02952 
02953     // Update progress cursor every 2k
02954     #if WIN32
02955     if (BytesRead > (LastProgressUpdate + 2048))
02956     {
02957         if (!ContinueSlowJob(BytesRead))
02958         {
02959             // Abort operation - make sure nodes are deleted and not added to the tree.
02960             ERROR(_R(IDT_IMPORT_USERABORT), FALSE);
02961         }
02962         else
02963         {
02964             LastProgressUpdate = BytesRead;
02965         }
02966     }
02967     #endif
02968 
02969     // Deal with all the functions that can appear in a windows metafile
02970     switch (pMetaRec->rdFunction)
02971     {
02972         case META_SETTEXTCHAREXTRA:
02973             AllUnderstood = FALSE;
02974             TRACEUSER( "Jonathan", _T("SETTEXTCHAREXTRA\n"));
02975             break;
02976 
02977         case META_SETTEXTCOLOR:
02978         {
02979             // Find out what colour we are setting text to
02980             COLORREF* pColour = (COLORREF*) pMetaRec->rdParm;
02981             DocColour NewColour(INT32(GetRValue(*pColour)), INT32(GetGValue(*pColour)),
02982                                 INT32(GetBValue(*pColour)));
02983 
02984             // Set the text colour
02985             TextColour = NewColour;
02986             break;
02987         }
02988 
02989         case META_SETTEXTJUSTIFICATION:
02990             AllUnderstood = FALSE;
02991             TRACEUSER( "Jonathan", _T("SETTEXTJUSTIFICATION\n"));
02992             break;
02993 
02994         case META_SETTEXTALIGN:
02995             //AllUnderstood = FALSE;
02996             break;
02997 
02998         case META_EXTTEXTOUT:
02999             if (!DecodeExtTextStory(pMetaRec))
03000                 return FALSE;
03001             break;
03002 
03003         case META_TEXTOUT:
03004             if (!DecodeTextStory(pMetaRec))
03005                 return FALSE;
03006             break;
03007 
03008 
03009 
03010         case META_SETSTRETCHBLTMODE:
03011             //This has no meaning in Camelot
03012             break;
03013 
03014         case META_DIBBITBLT:
03015             if (!DecodeDIBBitBlt(pMetaRec))
03016                 return FALSE;
03017             break;
03018 
03019         case META_DIBSTRETCHBLT:
03020             if (!DecodeDIBStretchBlt(pMetaRec))
03021                 return FALSE;
03022             break;
03023 
03024         case META_STRETCHDIB:
03025             if (!DecodeStretchDIB(pMetaRec))
03026                 return FALSE;
03027             break;
03028 
03029         case META_SETDIBTODEV:
03030             if (!DecodeDIBToDevice(pMetaRec))
03031                 return FALSE;
03032             break;
03033 
03034         case META_BITBLT:
03035             if (!DecodeBitBlt(pMetaRec))
03036                 return FALSE;
03037             break;
03038 
03039         case META_STRETCHBLT:
03040             if (!DecodeStretchBlt(pMetaRec))
03041                 return FALSE;
03042             break;
03043 
03044         case META_PATBLT:
03045             AllUnderstood = FALSE;
03046             TRACEUSER( "Jonathan", _T("PATBLT\n"));
03047             break;
03048 
03049         case META_DIBCREATEPATTERNBRUSH:
03050             AllUnderstood = FALSE;
03051             TRACEUSER( "Jonathan", _T("DIBCREATEPATTERNBRUSH\n"));
03052             break;
03053 
03054 
03055 
03056         case META_SETWINDOWORG:
03057         {
03058             // If metafile is not placeable, use this information
03059             if (!Placeable)
03060             {
03061                 // Remember params are in reverse order
03062                 MetaFileOrigin.y = (INT16) pMetaRec->rdParm[0];
03063                 MetaFileOrigin.x = (INT16) pMetaRec->rdParm[1];
03064                 YShift = 0;
03065             }
03066             break;
03067         }
03068 
03069         case META_SETWINDOWEXT:
03070         {
03071             // If metafile is not placeable, use this information
03072             //if (Placeable)
03073             {
03074                 INT16 YExtent = (INT16) pMetaRec->rdParm[0];
03075                 TRACEUSER( "Jonathan", _T("Extent - x=%d, y=%d\n"), pMetaRec->rdParm[1], pMetaRec->rdParm[0]);
03076                 if (YExtent<0 && !IsYExtentNegative)
03077                     FlipYCoords = TRUE;
03078 
03079                 if (YExtent>=0 && IsYExtentNegative)
03080                     FlipYCoords = TRUE;
03081 
03082                 if (FlipYCoords)
03083                     YShift = 0;
03084             }
03085             break;
03086         }
03087 
03088         case META_OFFSETWINDOWORG:
03089             AllUnderstood = FALSE;
03090             TRACEUSER( "Jonathan", _T("OFFSETWINDOWORG\n"));
03091             break;
03092 
03093         case META_SCALEWINDOWEXT:
03094             AllUnderstood = FALSE;
03095             TRACEUSER( "Jonathan", _T("SCALEWINDOWEXT\n"));
03096             break;
03097 
03098         case META_OFFSETVIEWPORTORG:
03099             AllUnderstood = FALSE;
03100             TRACEUSER( "Jonathan", _T("OFFSETVIEWPORTORG\n"));
03101             break;
03102 
03103         case META_SCALEVIEWPORTEXT:
03104             AllUnderstood = FALSE;
03105             TRACEUSER( "Jonathan", _T("SCALEVIEWPORTEXT\n"));
03106             break;
03107 
03108         case META_SETVIEWPORTORG:
03109             AllUnderstood = FALSE;
03110             TRACEUSER( "Jonathan", _T("SetViewportOrg\n"));
03111             break;
03112 
03113         case META_SETVIEWPORTEXT:
03114             AllUnderstood = FALSE;
03115             TRACEUSER( "Jonathan", _T("SetViewportExt\n"));
03116             break;
03117 
03118 
03119 
03120         case META_SETPOLYFILLMODE:
03121             if (((INT32) pMetaRec->rdParm[0]) == WINDING)
03122             {
03123                 // Non-zero winding rule
03124                 SetWindingRule(NonZeroWinding);
03125             }
03126             else
03127             {
03128                 // Even-odd winding
03129                 SetWindingRule(EvenOddWinding);
03130             }
03131             break;
03132 
03133         case META_POLYGON:
03134             if (!DecodePolygon(pMetaRec, TRUE))
03135                 // An error occured
03136                 return FALSE;
03137             break;
03138 
03139         case META_POLYPOLYGON:
03140             if (!DecodePolyPolygon(pMetaRec))
03141                 // An error occured
03142                 return FALSE;
03143             break;
03144 
03145         case META_POLYLINE:
03146             // Try and decode the polyline
03147             if (!DecodePolygon(pMetaRec, FALSE))
03148                 return FALSE;
03149             break;
03150 
03151 
03152 
03153         case META_ESCAPE:
03154             // Comment. Ignore this
03155             break;
03156 
03157 
03158 
03159         case META_SELECTOBJECT:
03160             if (!Handles->SelectObject(pMetaRec->rdParm[0]))
03161                 return FALSE;
03162             break;
03163 
03164         case META_DELETEOBJECT:
03165             if (!Handles->DeleteObject(pMetaRec->rdParm[0]))
03166                 return FALSE;
03167             break;
03168 
03169         case META_CREATEPALETTE:
03170             pPalette = (LOGPALETTE_16 *) pMetaRec->rdParm;
03171             if (!Handles->CreatePalette(pPalette))
03172                 // Error occured while creating this pen
03173                 return FALSE;
03174             break;
03175 
03176         case META_CREATEPATTERNBRUSH:
03177             if (!Handles->CreatePatternBrush(pMetaRec->rdParm))
03178                 // Error occured while creating this pen
03179                 return FALSE;
03180             break;
03181 
03182         case META_CREATEFONTINDIRECT:
03183             pFont = (LOGFONT_16 *) pMetaRec->rdParm;
03184             if (!Handles->CreateFontIndirect(pFont))
03185                 // Error occured while creating this pen
03186                 return FALSE;
03187             break;
03188 
03189         case META_CREATEREGION:
03190             if (!Handles->CreateRegion(pMetaRec->rdParm))
03191                 // Error occured while creating this pen
03192                 return FALSE;
03193             break;
03194 
03195         case META_CREATEPENINDIRECT:
03196             pPen = (LOGPEN_16 *) pMetaRec->rdParm;
03197             if (!Handles->CreatePen(pPen))
03198                 // Error occured while creating this pen
03199                 return FALSE;
03200             break;
03201 
03202         case META_CREATEBRUSHINDIRECT:
03203             pBrush = (LOGBRUSH_16 *) pMetaRec->rdParm;
03204             if (!Handles->CreateBrush(pBrush))
03205                 // Error occured while creating this brush
03206                 return FALSE;
03207             break;
03208 
03209 
03210 
03211         case META_LINETO:
03212             // Add a single straight line to the drawing
03213             if (!DecodeLineTo(pMetaRec))
03214                 return FALSE;
03215             break;
03216 
03217         case META_MOVETO:
03218             // Remember params are in reverse order
03219             CurrentPoint.y = (INT16) pMetaRec->rdParm[0];
03220             CurrentPoint.x = (INT16) pMetaRec->rdParm[1];
03221             TransformCoord(&CurrentPoint);
03222             break;
03223 
03224         case META_FLOODFILL:
03225             // This has no meaning in Camelot
03226             break;
03227 
03228         case META_EXTFLOODFILL:
03229             // This has no meaning in Camelot
03230             break;
03231 
03232         case META_ARC:
03233             AllUnderstood = FALSE;
03234             TRACEUSER( "Jonathan", _T("Arc\n"));
03235             break;
03236 
03237         case META_ELLIPSE:
03238             if (!DecodeEllipse(pMetaRec))
03239                 return FALSE;
03240             break;
03241 
03242         case META_PIE:
03243             AllUnderstood = FALSE;
03244             TRACEUSER( "Jonathan", _T("Pie\n"));
03245             break;
03246 
03247         case META_RECTANGLE:
03248             if (!DecodeRectangle(pMetaRec))
03249                 return FALSE;
03250             break;
03251 
03252         case META_ROUNDRECT:
03253             if (!DecodeRectangle(pMetaRec))
03254                 return FALSE;
03255             break;
03256 
03257         case META_CHORD:
03258             AllUnderstood = FALSE;
03259             TRACEUSER( "Jonathan", _T("Chord\n"));
03260             break;
03261 
03262         case META_SETPIXEL:
03263             // This has no meaning in Camelot
03264             break;
03265 
03266 
03267 
03268         case META_SELECTPALETTE:
03269             // This has no meaning in Camelot
03270             break;
03271 
03272         case META_REALIZEPALETTE:
03273             // This has no meaning in Camelot
03274             break;
03275 
03276         case META_ANIMATEPALETTE:
03277             // This has no meaning in Camelot
03278             break;
03279 
03280         case META_SETPALENTRIES:
03281             // This has no meaning in Camelot
03282             break;
03283 
03284         case META_RESIZEPALETTE:
03285             // This has no meaning in Camelot
03286             break;
03287 
03288 
03289 
03290         case META_FILLREGION:
03291             AllUnderstood = FALSE;
03292             TRACEUSER( "Jonathan", _T("FILLREGION\n"));
03293             break;
03294 
03295         case META_FRAMEREGION:
03296             AllUnderstood = FALSE;
03297             TRACEUSER( "Jonathan", _T("FRAMEREGION\n"));
03298             break;
03299 
03300         case META_INVERTREGION:
03301             AllUnderstood = FALSE;
03302             TRACEUSER( "Jonathan", _T("INVERTREGION\n"));
03303             break;
03304 
03305         case META_PAINTREGION:
03306             AllUnderstood = FALSE;
03307             TRACEUSER( "Jonathan", _T("PAINTREGION\n"));
03308             break;
03309 
03310         case META_SELECTCLIPREGION:
03311             AllUnderstood = FALSE;
03312             TRACEUSER( "Jonathan", _T("SELECTCLIPREGION\n"));
03313             break;
03314 
03315 
03316 
03317         case META_SAVEDC:
03318             // This has no meaning in Camelot
03319             break;
03320 
03321         case META_RESTOREDC:
03322             // This has no meaning in Camelot
03323             break;
03324 
03325         case META_SETROP2:
03326             // Find out what they want to set the pen to
03327             if ( ((INT32)pMetaRec->rdParm[0]) != R2_COPYPEN)
03328                 TRACEUSER( "Jonathan", _T("SetROP2 - Not Copy Pen!\n"));
03329             break;
03330 
03331 
03332 
03333         case META_EXCLUDECLIPRECT:
03334             //This has no meaning in Camelot
03335             break;
03336 
03337         case META_INTERSECTCLIPRECT:
03338             //This has no meaning in Camelot
03339             break;
03340 
03341         case META_OFFSETCLIPRGN:
03342             //This has no meaning in Camelot
03343             break;
03344 
03345 
03346 
03347         case META_SETMAPPERFLAGS:
03348             AllUnderstood = FALSE;
03349             TRACEUSER( "Jonathan", _T("SETMAPPERFLAGS\n"));
03350             break;
03351 
03352 
03353 
03354         case META_SETBKCOLOR:
03355             //This has no meaning in Camelot
03356             break;
03357 
03358         case META_SETBKMODE:
03359             // This has no meaning in Camelot
03360             break;
03361 
03362         case META_SETMAPMODE:
03363             CurrentMappingMode = (INT32) ((INT16) pMetaRec->rdParm[0]);
03364             TRACEUSER( "Jonathan", _T("SetMapMode: %d\n"), CurrentMappingMode);
03365             break;
03366 
03367         case META_SETRELABS:
03368             // This record appears in a lot of WMF files but does not seem
03369             // to break anything if it is ignored so I am stopping this
03370             // causing a warning to the the user
03371 //          AllUnderstood = FALSE;
03372             TRACEUSER( "Jonathan", _T("SETRELABS\n"));
03373             break;
03374 
03375         default:
03376             TRACEUSER( "Jonathan", _T("Unknown Function %x\n"), pMetaRec->rdFunction);
03377             return FALSE;
03378             break;
03379     }
03380 
03381     // Get the next metafile record;
03382     return 1;
03383 }
03384 
03385 /********************************************************************************************
03386 >   void MetaFileFilter::TransformCoord(DocCoord *C)
03387     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03388     Created:    29/03/94
03389     Inputs:     C - the coordinate to transform
03390     Outputs:    C - the transformed coordinate.
03391     Purpose:    Transform a metafile coordinate into a Camelot coordinate, by compensating
03392                 for the origin, and scaling the units.
03393                 Use MetaFileFilter::ScaleCoord() to scale without performing an origin
03394                 translation (useful for scaling dimensions).
03395     Errors:     ENSURE failure if a MM_ISOTROPIC or MM_ANISOTROPIC mapping mode is used.
03396     SeeAlso:    MetaFileFilter::ScaleCoord
03397 ********************************************************************************************/
03398 void MetaFileFilter::TransformCoord(DocCoord *C)
03399 {
03400     // Convert from metafile origin
03401     C->x -= MetaFileOrigin.x;
03402     C->y -= MetaFileOrigin.y;
03403 
03404     // Add in any offset that may be needed
03405     C->y += YShift;
03406 
03407     // Scale it
03408     ScaleCoord(C);
03409 }
03410 
03411 /********************************************************************************************
03412 >   void MetaFileFilter::ScaleCoord(DocCoord *C)
03413     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03414     Created:    29/03/94
03415     Inputs:     C - the coordinate to transform
03416     Outputs:    C - the transformed coordinate.
03417     Purpose:    Transform a metafile coordinate into a Camelot coordinate, by scaling the 
03418                 units.  NB.  NO origin translation is performed.
03419     Errors:     ENSURE failure if a MM_ISOTROPIC or MM_ANISOTROPIC mapping mode is used.
03420     SeeAlso:    MetaFileFilter::TransformCoord
03421 ********************************************************************************************/
03422 
03423 void MetaFileFilter::ScaleCoord(DocCoord *C)
03424 {
03425     // Scale the coordinates
03426     if (Placeable)
03427     {
03428         // Scale the X Coord
03429         C->x *= ScaleFactor;
03430         C->y *= ScaleFactor;
03431     }
03432     else
03433     {
03434         switch (CurrentMappingMode)
03435         {
03436             case MM_TEXT:
03437                 // Scale is in pixels
03438                 // Convert to millipoints
03439                 C->x *= ScaleFactor;
03440                 C->y *= ScaleFactor;
03441                 break;
03442 
03443             case MM_LOMETRIC:
03444                 // Scale of 0.1mm per unit
03445                 // Convert to millipoints: n * (72000 / (10 * 25.4))
03446                 C->x *= (72000 / 254);
03447                 C->y *= (72000 / 254);
03448                 break;
03449 
03450             case MM_HIMETRIC:
03451                 // Scale of 0.01mm per unit
03452                 // Convert to millipoints: n * (72000 / (100 * 25.4))
03453                 C->x *= (72000 / 2540);
03454                 C->y *= (72000 / 2540);
03455                 break;
03456 
03457             case MM_LOENGLISH:
03458                 // Scale of 0.01 inches per unit
03459                 // Convert to millipoints: (n / 100) * 72000
03460                 C->x *= (72000 / 100);
03461                 C->y *= (72000 / 100);
03462                 break;
03463 
03464             case MM_HIENGLISH:
03465                 // Scale of 0.001 inches per unit
03466                 // Convert to millipoints: (n / 1000) * 72000
03467                 C->x *= (72000 / 1000);
03468                 C->y *= (72000 / 1000);
03469                 break;
03470 
03471             case MM_TWIPS:
03472                 // Scale of 1/1440th of an inch per unit
03473                 // Convert to millipoints: (n / 1440) * 72000
03474                 C->x *= (72000 / 1440);
03475                 C->y *= (72000 / 1440);
03476                 break;
03477 
03478             //case MM_ISOTROPIC:
03479             //  ENSURE(FALSE, "Can't cope with ISOTROPIC mapping in metafiles!");
03480             //  break;
03481 
03482             //case MM_ANISOTROPIC:
03483             //  ENSURE(FALSE, "Can't cope with ANISOTROPIC mapping in metafiles!");
03484             //  break;
03485 
03486             default:
03487                 C->x *= ScaleFactor;
03488                 C->y *= ScaleFactor;
03489                 break;
03490         }
03491     }
03492 
03493     // Scale the Y Coord
03494     if (FlipYCoords)
03495         C->y = -C->y;
03496 }
03497 
03498 /********************************************************************************************
03499 >   BOOL MetaFileFilter::AddAttributes(NodePath *pPath)
03500 
03501     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03502     Created:    18/11/93
03503     Inputs:     pPath - pointer to the NodePath object to add attributes to.
03504                 pHeader - pointer to the Draw file object header which describes the path
03505                 attributes.
03506     Returns:    TRUE if the attributes were added ok, FALSE if not.
03507     Purpose:    Add attributes to the path object specified.  The attributes are optimised
03508                 so that if they are the same as the document's default attributes, they are
03509                 not applied.
03510                 The attributes applied are line and fill colour, and line style.
03511     Errors:     Fails (returns FALSE) if not enough memory to add attributes.
03512     Scope:      Private
03513 
03514 ********************************************************************************************/
03515 BOOL MetaFileFilter::AddAttributes(Node* pNewNode)
03516 {
03517     // If not filled, then set the ignore bit on the fill attribute.
03518     if (pNewNode->IS_KIND_OF(NodePath))
03519     {
03520         NodePath* pPath = (NodePath*) pNewNode;
03521         if (!pPath->InkPath.IsFilled)
03522             CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = TRUE;
03523     }
03524         
03525     // Add attributes to the path, if they are different from the default...
03526     BOOL Result = AttributeManager::ApplyBasedOnDefaults(pNewNode, CurrentAttrs);
03527 
03528     // Enable the fill attribute again
03529     CurrentAttrs[ATTR_FILLGEOMETRY].Ignore = FALSE;
03530 
03531     // Return success or failure
03532     return Result;
03533 }
03534 
03535 
03536 /********************************************************************************************
03537 >   BOOL MetaFileFilter::DoExport(Operation*, CCLexFile* pFile, PathName* pPath, Document*,
03538                                   BOOL ShowOptions)
03539     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
03540     Created:    15/3/95
03541     Inputs:     pOp - the operation that started the export off
03542                 pFile - the file to put the exported data into
03543                 pPath - the pathname of the file to be exported to
03544                 pDoc - the document to export
03545                 ShowOptions - Show the export options dialogue.
03546     Returns:    TRUE if it worked, FALSE if there was a problem
03547     Purpose:    To actually export into a metafile
03548     SeeAlso:    Filter::DoExport
03549 ********************************************************************************************/
03550 BOOL MetaFileFilter::DoExport(Operation*, CCLexFile* pFile, PathName* pPath, Document* pDoc,
03551                               BOOL ShowOptions)
03552 {
03553     // Used to open the file up before starting DoExport. But this meant a cancel on the export
03554     // options dialog had filled the file, if it was already present. So now up up here if
03555     // not open already. In the PreviewBitmap case the file will already be open.
03556     if (!pFile->isOpen())
03557     {
03558         if (pFile->IsKindOf(CC_RUNTIME_CLASS(CCDiskFile)))
03559         {
03560             BOOL ok = OpenExportFile((CCDiskFile*) pFile, pPath);
03561             if (!ok) return FALSE;
03562         }
03563         else
03564         {
03565             TRACEUSER( "JustinF", _T("Tried to open non-CCDiskFile in MetaFileFilter::DoExport\n"));
03566             return FALSE;
03567         }
03568     }
03569 
03570     // Get pointer to the spread to export.
03571     Spread* pSpread = GetFirstSpread(pDoc);
03572     ExportClipRect.MakeEmpty();
03573 
03574     // Set up device context and render region for this export.
03575     // This will show a progress hourglass for the objects being rendered
03576     if (!PrepareToExport(pFile, pSpread))
03577     {
03578         CleanUpAfterExport();
03579         return FALSE;
03580     }
03581 
03582     // put out some sensible stuff on the front
03583     MetafileDC.SetMapMode(pMetaView->GetMetafileMapMode());
03584 
03585     // Export the data to the file
03586     BOOL ok = ExportRender(ExportRegion);
03587     HMETAFILE hMetafile = NULL;
03588 
03589     // If there have been no errors so far, find out about the metafile
03590     if (ok)
03591     {
03592         // get a metafile handle from the metafile DC
03593         hMetafile = MetafileDC.Close();
03594         if (hMetafile == NULL)
03595         {
03596             ERROR1RAW( _R(IDE_MF_NOCLOSE) );
03597             ok = FALSE;
03598         }
03599     }
03600 
03601     // and clean up
03602     if (!ok)
03603     {
03604         if (hMetafile) DeleteMetaFile(hMetafile);
03605         CleanUpAfterExport();
03606         return FALSE;
03607     }
03608 
03609     // Put up a progress display/hourglass
03610     // (0 - 100, FALSE => no delay, show it NOW!, use the filters export message)
03611     String_64 ProgressString(_R(IDT_EXPORTMSG_METAFILE2));
03612     ProgressString = GetExportProgressString(pFile, _R(IDT_EXPORTMSG_METAFILE2));
03613     BeginSlowJob(100, FALSE, &ProgressString);
03614 
03615     // build standard placeable metafile header
03616     METAFILEHEADER Header;
03617     Header.key      = METAFILEHEADERKEY;
03618     Header.hmf      = 0;
03619     Header.inch     = pMetaView->GetMetafileDPI();
03620     Header.reserved = 0L;
03621     Header.checksum = 0;
03622 
03623     // And fill in the details about the Bounding rect
03624     FIXED16 PixelSize;
03625     pMetaView->GetPixelSize(&PixelSize, &PixelSize);
03626     INT32 Size = PixelSize.MakeLong();
03627     Header.bbox.left   = (short) (ExportClipRect.lo.x / Size);
03628     Header.bbox.top    = (short) (ExportClipRect.lo.y / Size);
03629     Header.bbox.right  = (short) (ExportClipRect.hi.x / Size);
03630     Header.bbox.bottom = (short) (ExportClipRect.hi.y / Size);
03631 
03632     // calculate checksum as Word checks this
03633     LPWORD p = (LPWORD) &Header;
03634     INT32 i = 10;
03635     while (i--)
03636     {
03637         // Just OR together all the WORDs in the Header
03638         Header.checksum ^= *p++;
03639     }
03640 
03641     // actually write to the file
03642     ok = WriteToFile( hMetafile, &Header );
03643     DeleteMetaFile( hMetafile );
03644 
03645     // All done - deallocate dynamic objects, stop the progress display/hourglass
03646     // and return success. (Also closes file).
03647     CleanUpAfterExport();
03648     EndSlowJob();       
03649 
03650     // return, saying if it worked or not
03651     return ok;
03652 }
03653 
03654 
03655 /********************************************************************************************
03656 >   BOOL MetaFileFilter::DoExport(Operation*, CCLexFile* pFile, Document* pDoc,
03657                                   METAFILEPICT* pMetaInfo)
03658     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
03659     Created:    4/7/95
03660     Inputs:     pFile - Dummy param. Need to pass in something, but we try not to use it
03661                 pDoc - the document to render
03662                 pMetaInfo - the info about the metafile we will create.
03663     Outputs:    pMetaInfo - the info about the metafile we will create.
03664     Returns:    TRUE if it worked, FALSE if not
03665     Purpose:    This is a special version of the DoExport function that is used to render in
03666                 a memory metafile (not a real file, like normal).
03667 ********************************************************************************************/
03668 BOOL MetaFileFilter::DoExport(Operation*, CCLexFile* pFile, Document* pDoc, METAFILEPICT* pMetaInfo)
03669 {
03670     // Get pointer to the spread to export.
03671     Spread *pSpread = GetFirstSpread(pDoc);
03672     ExportClipRect.MakeEmpty();
03673 
03674     // Set up device context and render region for this export.
03675     // This will show a progress hourglass for the objects being rendered
03676     if (!PrepareToExport(NULL, pSpread))
03677     {
03678         CleanUpAfterExport();
03679         return FALSE;
03680     }
03681 
03682     // put out some sensible stuff on the front
03683     MetafileDC.SetMapMode(pMetaView->GetMetafileMapMode());
03684     pMetaInfo->mm = pMetaView->GetMetafileMapMode();
03685 
03686     // Export the data to the file
03687     BOOL ok = ExportRender(ExportRegion);
03688     HMETAFILE hMetafile = NULL;
03689 
03690     if (ok)
03691     {
03692         // get a metafile handle from the metafile DC
03693         hMetafile = MetafileDC.Close();
03694         if (hMetafile==NULL)
03695         {
03696             ERROR1RAW(_R(IDE_MF_NOCLOSE));
03697             ok = FALSE;
03698         }
03699     }
03700 
03701     // If at this point, something has gone wrong, tidy up
03702     if (!ok)
03703     {
03704         // Get rid of the metafile
03705         if (hMetafile)
03706             DeleteMetaFile(hMetafile);
03707 
03708         // Tidy up and fail
03709         CleanUpAfterExport();
03710         return FALSE;
03711     }
03712 
03713     // Put up a progress display/hourglass
03714     String_64 ProgressString(_R(IDT_EXPORTMSG_METAFILE2));
03715     ProgressString = GetExportProgressString(pFile, _R(IDT_EXPORTMSG_METAFILE2));
03716     BeginSlowJob(100, FALSE, &ProgressString);
03717 
03718     // Fill in the info about the metafile that we know
03719     // make it bigger as the coords we use are smaller than most.
03720     FIXED16 PixelSize;
03721     pMetaView->GetPixelSize(&PixelSize, &PixelSize);
03722     INT32 Size = PixelSize.MakeLong();
03723     pMetaInfo->xExt = ExportClipRect.Width() / Size;
03724     pMetaInfo->yExt = ExportClipRect.Height() / Size;
03725     pMetaInfo->hMF = hMetafile;
03726 
03727     // All done - deallocate dynamic objects, stop the progress display/hourglass
03728     // and return success. (Also closes file).
03729     CleanUpAfterExport();
03730     EndSlowJob();       
03731 
03732     return ok;
03733 }
03734 
03735 
03736 /********************************************************************************************
03737 >   BOOL MetaFileFilter::PrepareToExport(CCLexFile* pFile, Spread* pSpread)
03738     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
03739     Created:    15/3/95
03740     Inputs:     See base class version.
03741     Returns:    See base class version.
03742     Purpose:    To get ready to export a metafile. Most importantly creates an
03743                 ExportRegion, but has to create other support items first.
03744     SeeAlso:    Filter::DoExport
03745 ********************************************************************************************/
03746 BOOL MetaFileFilter::PrepareToExport(CCLexFile* pFile, Spread* pSpread)
03747 {
03748     // the member variable OutputFile is deliberately a vanilla CCLexFile because
03749     // metafile output must be made to work to all file types, especially memory files
03750     OutputFile = pFile;
03751 
03752     // work out the clip rect by exporting the whole drawing
03753     // Start out with an empty clip rect
03754     DocRect SpreadRect;
03755     SpreadRect.MakeEmpty();
03756 
03757     // We need to take into account the fact that some layers may not be visible
03758     Node* pNode = pSpread->FindFirstChild();
03759     while (pNode!=NULL)
03760     {
03761         // See if this is a layer
03762         if (IS_A(pNode, Layer))
03763         {
03764             // It sure is... lets see if it is visible
03765             Layer* pLayer = (Layer*) pNode;
03766             if (pLayer->IsVisible())
03767             {
03768                 // This one is visible, so union it in
03769                 DocRect LayerRect = pLayer->GetBoundingRect();
03770                 SpreadRect = SpreadRect.Union(LayerRect);
03771             }
03772         }
03773 
03774         // Get the next sibling
03775         pNode = pNode->FindNext();
03776     }
03777 
03778     // Set the clip rect
03779     DocRect ClipRect = SpreadRect;
03780     ExportClipRect = SpreadRect;
03781 
03782     // we need a View to Attach to, so that:
03783     //      default Quality setting
03784     //      CalcPixelWidth etc get called
03785     //View *pView = View::GetCurrent();
03786     pMetaView = new MetafileView();
03787     if (pMetaView==NULL)
03788         return FALSE;
03789 
03790     // Init the view
03791     if (!pMetaView->Init())
03792     {
03793         delete pMetaView;
03794         pMetaView = NULL;
03795         return FALSE;
03796     }
03797 
03798     // now lets get a render region suitably contructed
03799     FIXED16 XScale, YScale;
03800     pMetaView->GetScaleFactor(&XScale, &YScale);
03801     Matrix Identity(XScale, YScale);
03802 
03803     // Don't use view scale; set to 1
03804     FIXED16 Scale(1);
03805 
03806     // Create the region
03807     ExportRegion = OSRenderRegion::Create(ClipRect, Identity, Scale, RENDERTYPE_METAFILE16, pMetaView, TRUE );
03808     if (ExportRegion == NULL)
03809         // Error already set by new, so just return
03810         return FALSE;
03811 
03812     // lets create a metafile DC now
03813     if (!MetafileDC.Create( NULL ))                                 // create it in memory
03814         ERROR1( FALSE, _R(IDE_MF_NOCREATE) );
03815 
03816     // need a refernce DC - don't just use the view window because it will get messed up
03817     // We use a fresh new screen DC
03818     if (!ReferenceDC.CreateIC( "DISPLAY", NULL, NULL, NULL ))
03819         ERROR1( FALSE, _R(IDE_MF_NOCREATE) );
03820 
03821     // if we don't do this then a load of Getxxx calls will fail
03822     MetafileDC.SetAttribDC( ReferenceDC.m_hDC );
03823 
03824     // this (i) stops paper etc from being rendered, and (ii) stops background rendering screwing us up
03825     MetafileDC.m_bPrinting = TRUE;
03826 
03827     // Attach to the right device
03828     return ExportRegion->AttachDevice(pMetaView, &MetafileDC, pSpread);
03829 }
03830 
03831 /********************************************************************************************
03832 >   void MetaFileFilter::CleanUpAfterExport()
03833     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
03834     Created:    15/3/95
03835     Inputs:     See base class version.
03836     Returns:    See base class version.
03837     Purpose:    Tidys up outstanding items created in PrepareToExport
03838 ********************************************************************************************/
03839 void MetaFileFilter::CleanUpAfterExport()
03840 {
03841     // Clean up the view
03842     if (pMetaView!=NULL)
03843     {
03844         delete pMetaView;
03845         pMetaView = NULL;
03846     }
03847 
03848     // Clean up the metafile DC
03849     if (MetafileDC.m_hDC)
03850     {
03851         MetafileDC.DeleteDC();
03852     }
03853 
03854     // and the attribute DC
03855     if (ReferenceDC.m_hDC)
03856     {
03857         ReferenceDC.DeleteDC();
03858     }
03859 
03860     // and make sure the file is closed
03861     if (OutputFile)
03862     {
03863         OutputFile->close();
03864         // *dont* delete OutputFile because it turns out to be a static object...
03865         OutputFile = NULL;
03866     }
03867 }
03868 
03869 /********************************************************************************************
03870 >   BOOL MetaFileFilter::WriteToFile( HMETAFILE hMetafile, METAFILEHEADER *PlaceableHeader )
03871     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
03872     Created:    15/3/95
03873     Inputs:     A metafile handle to write out the data from and a placeable header to
03874                 write out as well.
03875     Returns:    TRUE worked, FALSE failed (error set)
03876     Purpose:    Get the metafile onto the disk. Inherited classes could override this for
03877                 further nefarious purposes e.g. output via Aldus filters
03878 ********************************************************************************************/
03879 BOOL MetaFileFilter::WriteToFile( HMETAFILE hMetafile, METAFILEHEADER *PlaceableHeader )
03880 {
03881     // write header first
03882     OutputFile->write( PlaceableHeader, sizeof(METAFILEHEADER) );
03883 
03884     // now the actual data
03885     UINT32 size = GetMetaFileBitsEx( hMetafile, 0, NULL );          // does NOT invalidate hMetafile
03886     ERROR1IF( size==0, FALSE, _R(IDE_MF_NOMEMLOCK) );
03887 
03888     LPVOID block = CCMalloc( size );
03889     ERROR1IF( block==NULL, FALSE, _R(IDS_OUT_OF_MEMORY) );
03890 
03891     size = GetMetaFileBitsEx( hMetafile, size, block );
03892     if (size)
03893     {
03894         OutputFile->write( block, size );
03895         CCFree( block );
03896         return TRUE;
03897     }
03898     else
03899     {
03900         CCFree( block );
03901         ERROR1( FALSE, _R(IDE_MF_NOMEMLOCK) );
03902     }
03903 }
03904 
03906 // Aldus format filter class was here.  As none of it   //
03907 // was being used I have deleted all of it.  See        //
03908 // SourceSafe for Camelot2000 for the code.  There are  //
03909 // also some docs in the docs folder (AldusFilter.doc   //
03910 // or similar).  I think the idea of the filter was that//
03911 // we would be able to open lots of vector file formats //
03912 // by emulating the Aldus filter DLL format.            //
03913 //                          -- Jonthan 12/10/2000       //

Generated on Sat Nov 10 03:48:40 2007 for Camelot by  doxygen 1.4.4