//----------------------------------------------------------------------------
// ObjectWindows
// Copyright (c) 1992, 1997 by Borland International, All Rights Reserved
//
/// \file
/// Implementation of TMetaFilePict class
//----------------------------------------------------------------------------
#include <owl/pch.h>
#include <owl/metafile.h>
#include <owl/gdiobjec.h>
#include <owl/clipboar.h>
#include <owl/except.h>
#include <owl/file.h>
#if defined(__BORLANDC__)
# pragma option -w-ccc // Disable "Condition is always true/false"
#endif
using namespace std;
namespace owl {
OWL_DIAGINFO;
DIAG_DECLARE_GROUP(OwlGDI); // General GDI diagnostic group
/// Constant for checking validity of a METAFILEHEADER
//
const uint32 TMetaFilePict::MFHeaderKey = 0x9AC6CDD7L;
// header description
static TBinField MetaFileHeaderField[]={
{varLONG, 4, 1}, /* DWORD key */
{varSHORT,2, 1}, /* WORD hmf unused (0) */
{varSHORT,2, 4}, /* RECT16 bbox; // bounding rectangle */
{varSHORT,2, 1}, /* WORD inch; // units per inch */
{varLONG, 4, 1}, /* DWORD reserved; // unused (0) */
{varSHORT,2, 1}, /* WORD checksum; // XOR of previous fields */
{varEnd,0,0}
};
//
/// Creates a TMetaFilePict object using the given handle argument.
//
TMetaFilePict::TMetaFilePict(HMETAFILE handle, TAutoDelete autoDelete)
:
TGdiBase(handle, autoDelete),
Extent(0,0),
Placeable(false)
{
Mm = MM_ANISOTROPIC;
}
//
/// Creates a TMetaFilePict object for the metafile stored in the named file.
//
TMetaFilePict::TMetaFilePict(const tstring& filename)
:
Extent(0,0),
Placeable(false)
{
TFile file;
file.Open(filename,TFile::ReadOnly|TFile::OpenExisting|TFile::PermRead);
file.ReadStruct(&MFHeader, MetaFileHeaderField, boLittle_Endian);
// Determine whether this file begins with a valid METAFILEHEADER
// struct and load the file accordingly.
//
if ((MFHeader.key == MFHeaderKey)
&& (MFHeader.checksum == CalcHeaderChecksum(MFHeader)))
{
// Determine size of metafile data
//
TFileStatus status;
file.GetStatus(status);
long size = status.size - sizeof(METAFILEHEADER);
// Convert the data to a metafile
//
HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, size);
if (!hMem)
TXOutOfMemory::Raise();
uint8 * pMem = (uint8 *)GlobalLock(hMem);
file.Read((void *)pMem, size);
Handle = SetMetaFileBitsEx(size, pMem);
GlobalUnlock(hMem);
GlobalFree(hMem);
// Remember that this metafile comes with a placeable header
// (in other words, MFHeader holds valid data)
//
if (Handle)
Placeable = true;
// Placeable metafiles are meant to be played back in
// the unconstrained mapping mode. The header tells
// the desired size and aspect ratio.
//
Mm = MM_ANISOTROPIC;
// Set metafile dimensions according to info in header
//
Extent.cx = MFHeader.bbox.right - MFHeader.bbox.left;
Extent.cy = MFHeader.bbox.bottom - MFHeader.bbox.top;
// Convert dimensions to HIMETRIC units (.001 cm)
//
Extent.cx = MulDiv(Extent.cx, 2540, MFHeader.inch);
Extent.cy = MulDiv(Extent.cy, 2540, MFHeader.inch);
}
else {
Mm = MM_ANISOTROPIC;
Handle = ::GetMetaFile(filename.c_str());
}
ShouldDelete = true;
file.Close();
CheckValid();
}
//
/// Constructs a TMetaFilePict that represents the metafilepict on the clipboard.
/// Should be copied if metafile needs to be kept.
//
TMetaFilePict::TMetaFilePict(const TClipboard&)
:
Extent(0,0),
Placeable(false)
{
HGLOBAL hmfp = ::GetClipboardData(CF_METAFILEPICT);
METAFILEPICT * mfp = (METAFILEPICT *)::GlobalLock(hmfp);
if (mfp) {
Mm = mfp->mm;
Extent = TSize(mfp->xExt, mfp->yExt);
Handle = mfp->hMF;
::GlobalUnlock(hmfp);
}
else
Handle = 0;
ShouldDelete = false;
CheckValid();
}
//
/// Creates a TMetaFilePict object for the memory-based metafile specified by data.
/// The data buffer must hold a metafile of length size bytes.
//
TMetaFilePict::TMetaFilePict(uint size, void* data)
:
TGdiBase(::SetMetaFileBitsEx(size, (LPBYTE)data), NoAutoDelete),
Extent(0,0),
Placeable(false)
{
CheckValid();
Mm = MM_ANISOTROPIC;
}
//
/// Copies the metafile src to the named file. If filename is 0 (the default), the
/// metafile is copied to a memory-based metafile.
//
TMetaFilePict::TMetaFilePict(const TMetaFilePict& src, LPCTSTR fileName)
:
TGdiBase(::CopyMetaFile(src, fileName), AutoDelete),
Extent(src.Extent),
Placeable(false)
{
CheckValid();
Mm = src.Mm;
}
//
/// String-aware overload
/// If the filename is empty, the metafile is copied to a memory-based metafile.
//
TMetaFilePict::TMetaFilePict(const TMetaFilePict& src, const tstring& fileName)
:
TGdiBase(::CopyMetaFile(src, fileName.empty() ? 0 : fileName.c_str()), AutoDelete),
Extent(src.Extent),
Placeable(false)
{
CheckValid();
Mm = src.Mm;
}
//
/// Deletes the metafile.
//
TMetaFilePict::~TMetaFilePict()
{
if (ShouldDelete && Handle)
::DeleteMetaFile(HMETAFILE(Handle));
}
//
/// Reads the fields in the file header structure of a placeable
/// metafile and computes a checksum value for verifying the
/// header's integrity.
//
uint16
TMetaFilePict::CalcHeaderChecksum(const METAFILEHEADER& header)
{
LPWORD lpw; // pointer to words in header
uint16 checksum = 0;
for (lpw = (LPWORD)&header;
lpw < (LPWORD)&header.checksum;
++lpw)
{
// XOR current checksum with next field
//
checksum ^= *lpw;
}
return checksum;
}
//
/// Retrieves the contents of the metafile associated with this object
/// and copies them (up to size bytes) to the data buffer. If data is nonzero and
/// the call succeeds, the actual number of bytes copied is returned. If data is 0,
/// a successful call returns the number of bytes required by the buffer. A return
/// value of 0 always indicates a failure.
//
uint32
TMetaFilePict::GetMetaFileBitsEx(uint size, void* data)
{
return ::GetMetaFileBitsEx(HMETAFILE(Handle), size, (LPBYTE)data);
}
//
/// Calculates target play size based on info from the metafilepict (if any)
/// and default target size as necessary
//
TSize
TMetaFilePict::CalcPlaySize(TDC& dc, const TSize& defSize) const
{
// Given a fixed mapping mode, return precalculated extents
//
if (Mm != MM_ISOTROPIC && Mm != MM_ANISOTROPIC) {
WARNX(OwlGDI, (Extent.X() == 0) || (Extent.Y() == 0), 0, "Constrained metafile extent == 0");
return Extent; // Assumes extents were calculated correctly.
}
//
// Metafile uses partially constrained or unconstrained mapping mode
//
// If no extent info given, then use defaults
//
if (Extent.X() == 0) {
WARNX(OwlGDI, (defSize.X() == 0) || (defSize.Y() == 0), 0, "Metafile using default extent == 0");
return defSize;
}
// Use positive extents scaled to 0.01mm units
//
else if (Extent.cx > 0) {
return TSize(
int(long(Extent.cx)*dc.GetDeviceCaps(HORZRES)/dc.GetDeviceCaps(HORZSIZE)/100),
int(long(Extent.cy)*dc.GetDeviceCaps(VERTRES)/dc.GetDeviceCaps(VERTSIZE)/100)
);
}
// Use negative extents scaled to 0.01mm units w/ aspect ratio scaling
//
else {
long xscale = 100L * defSize.cx *
dc.GetDeviceCaps(HORZSIZE)/dc.GetDeviceCaps(HORZRES) / -Extent.cx;
long yscale = 100L * defSize.cy *
dc.GetDeviceCaps(VERTSIZE)/dc.GetDeviceCaps(VERTRES) / -Extent.cy;
long scale = std::min(xscale, yscale);
return TSize(
int(long(-Extent.cx)*scale*dc.GetDeviceCaps(HORZRES)/dc.GetDeviceCaps(HORZSIZE) / 100),
int(long(-Extent.cy)*scale*dc.GetDeviceCaps(VERTRES)/dc.GetDeviceCaps(VERTSIZE) / 100)
);
}
}
//
/// Plays this metafile onto a dc, possibly using a default size if this
/// metafile doesn't have one. Does not save dc state.
//
bool
TMetaFilePict::PlayOnto(TDC& dc, const TSize& defSize) const
{
// Set target dc's mapping mode to this metafile's if there is one
//
if (Mm)
dc.SetMapMode(Mm);
// Set the viewport extent to the area that the metafile will fill
//
if ((Mm == MM_ISOTROPIC || Mm == MM_ANISOTROPIC) && Extent.cx && Extent.cy)
// if (Mm == MM_ISOTROPIC || Mm == MM_ANISOTROPIC)
dc.SetViewportExt(CalcPlaySize(dc, defSize));
return ::PlayMetaFile(dc, *this);
}
//
/// Moves this metafile to the clipboard inside of a metafilepict struct.
/// Ownership of the metafilepict as well as the metafile is passed to the
/// clipboard.
//
void
TMetaFilePict::ToClipboard(TClipboard& clipboard, unsigned mapMode,
const TSize& extent)
{
HGLOBAL hmfp = ::GlobalAlloc(GMEM_MOVEABLE, sizeof(METAFILEPICT));
if (!hmfp)
TXOutOfMemory::Raise();
METAFILEPICT * mfp = (METAFILEPICT *)::GlobalLock(hmfp);
mfp->mm = mapMode;
mfp->xExt = extent.cx;
mfp->yExt = extent.cy;
mfp->hMF = (HMETAFILE)Handle;
::GlobalUnlock(hmfp);
clipboard.SetClipboardData(CF_METAFILEPICT, hmfp);
ShouldDelete = false;
}
//
/// Alias for an existing enhanced metafile handle.
//
TEnhMetaFilePict::TEnhMetaFilePict(HENHMETAFILE handle, TAutoDelete autoDelete)
:
TGdiBase(handle, autoDelete)
{
}
//
/// Creates an enhanced metafile from an external file.
//
TEnhMetaFilePict::TEnhMetaFilePict(const tstring& filename)
:
TGdiBase(::GetEnhMetaFile(filename.c_str()), AutoDelete)
{
}
//
/// Copies a metafile.
/// If the filename is 0 (the default), then the metafile is copied to a memory-based metafile.
//
TEnhMetaFilePict::TEnhMetaFilePict(const TEnhMetaFilePict& metafilepict,
LPCTSTR filename)
:
TGdiBase(::CopyEnhMetaFile(metafilepict, filename), AutoDelete)
{
}
//
/// String-aware overload
/// If the filename is empty, the metafile is copied to a memory-based metafile.
//
TEnhMetaFilePict::TEnhMetaFilePict(const TEnhMetaFilePict& metafilepict, const tstring& fileName)
: TGdiBase(::CopyEnhMetaFile(metafilepict, fileName.empty() ? 0 : fileName.c_str()), AutoDelete)
{}
//
/// Creates metafile from buffer.
//
TEnhMetaFilePict::TEnhMetaFilePict(uint bytes, const void* buffer)
:
TGdiBase(::SetEnhMetaFileBits(bytes, (const BYTE*)buffer), AutoDelete)
{
}
//
/// Destroys the enhanced metafile picture.
//
TEnhMetaFilePict::~TEnhMetaFilePict()
{
if (ShouldDelete && Handle)
::DeleteEnhMetaFile(HENHMETAFILE(Handle));
}
//
/// Plays the metafile onto a device context.
//
bool
TEnhMetaFilePict::PlayOnto(TDC& dc, const TRect* rect) const
{
return ::PlayEnhMetaFile(dc, *this, rect);
}
} // OWL namespace
/* ========================================================================== */
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: MFHeader.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: MFHeader.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: MFHeader.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: MFHeader.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: MFHeader.