You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5256 lines
155 KiB
5256 lines
155 KiB
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1999 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
*
|
|
* MetaFile.cpp
|
|
*
|
|
* Abstract:
|
|
*
|
|
* Metafile object handling
|
|
*
|
|
* Created:
|
|
*
|
|
* 4/14/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hpp"
|
|
#include "..\imaging\api\comutils.hpp"
|
|
|
|
#define META_FORMAT_ENHANCED 0x10000 // Windows NT format
|
|
|
|
VOID
|
|
FrameToMM100(
|
|
const GpRectF * frameRect,
|
|
GpPageUnit frameUnit,
|
|
GpRectF & frameRectMM100,
|
|
REAL dpiX, // only used for pixel case
|
|
REAL dpiY
|
|
);
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Determine if the REAL points can be converted to GpPoint16 points without
|
|
* losing accuracy. If so, then do the conversion, and set the flags to say
|
|
* we're using 16-bit points.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] points - the REAL points to try to convert
|
|
* [IN] count - the number of points
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
MetafilePointData::MetafilePointData(
|
|
const GpPointF * points,
|
|
INT count
|
|
)
|
|
{
|
|
ASSERT((count > 0) && (points != NULL));
|
|
|
|
// Assume that the conversion to GpPoint16 will fail
|
|
PointData = (BYTE *)points;
|
|
PointDataSize = count * sizeof(points[0]);
|
|
Flags = 0;
|
|
AllocedPoints = NULL;
|
|
|
|
GpPoint16 * points16 = PointBuffer;
|
|
|
|
if (count > GDIP_POINTDATA_BUFFERSIZE)
|
|
{
|
|
AllocedPoints = new GpPoint16[count];
|
|
if (AllocedPoints == NULL)
|
|
{
|
|
return; // live with REAL data
|
|
}
|
|
points16 = AllocedPoints;
|
|
}
|
|
|
|
GpPoint16 * curPoint16 = points16;
|
|
INT i = count;
|
|
|
|
do
|
|
{
|
|
curPoint16->X = (INT16)GpRound(points->X);
|
|
curPoint16->Y = (INT16)GpRound(points->Y);
|
|
|
|
if (!IsPoint16Equal(curPoint16, points))
|
|
{
|
|
return; // the point data doesn't fit in 16 bits per value
|
|
}
|
|
curPoint16++;
|
|
points++;
|
|
} while (--i > 0);
|
|
|
|
// We succeeded in converting the point data to 16 bits per value
|
|
PointData = (BYTE *)points16;
|
|
PointDataSize = count * sizeof(points16[0]);
|
|
Flags = GDIP_EPRFLAGS_COMPRESSED;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Determine if the REAL rects can be converted to GpRect16 points without
|
|
* losing accuracy. If so, then do the conversion, and set the flags to say
|
|
* we're using 16-bit rects.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] rects - the REAL rects to try to convert
|
|
* [IN] count - the number of rects
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
MetafileRectData::MetafileRectData(
|
|
const GpRectF * rects,
|
|
INT count
|
|
)
|
|
{
|
|
ASSERT((count > 0) && (rects != NULL));
|
|
|
|
// Assume that the conversion to GpRect16 will fail
|
|
RectData = (BYTE *)rects;
|
|
RectDataSize = count * sizeof(rects[0]);
|
|
Flags = 0;
|
|
AllocedRects = NULL;
|
|
|
|
GpRect16 * rects16 = RectBuffer;
|
|
|
|
if (count > GDIP_RECTDATA_BUFFERSIZE)
|
|
{
|
|
AllocedRects = new GpRect16[count];
|
|
if (AllocedRects == NULL)
|
|
{
|
|
return; // live with REAL data
|
|
}
|
|
rects16 = AllocedRects;
|
|
}
|
|
|
|
GpRect16 * curRect16 = rects16;
|
|
INT i = count;
|
|
|
|
do
|
|
{
|
|
curRect16->X = (INT16)GpRound(rects->X);
|
|
curRect16->Y = (INT16)GpRound(rects->Y);
|
|
curRect16->Width = (INT16)GpRound(rects->Width);
|
|
curRect16->Height = (INT16)GpRound(rects->Height);
|
|
|
|
if (!IsRect16Equal(curRect16, rects))
|
|
{
|
|
return; // the rect data doesn't fit in 16 bits per value
|
|
}
|
|
curRect16++;
|
|
rects++;
|
|
} while (--i > 0);
|
|
|
|
// We succeeded in converting the rect data to 16 bits per value
|
|
RectData = (BYTE *)rects16;
|
|
RectDataSize = count * sizeof(rects16[0]);
|
|
Flags = GDIP_EPRFLAGS_COMPRESSED;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// classes for handling recording of objects within the metafile
|
|
|
|
class MetafileRecordObject
|
|
{
|
|
friend class MetafileRecordObjectList;
|
|
protected:
|
|
const GpObject * ObjectPointer;
|
|
UINT Uid;
|
|
ObjectType Type;
|
|
UINT Next;
|
|
UINT Prev;
|
|
|
|
public:
|
|
MetafileRecordObject()
|
|
{
|
|
ObjectPointer = NULL;
|
|
Uid = 0;
|
|
Type = ObjectTypeInvalid;
|
|
Next = GDIP_LIST_NIL;
|
|
Prev = GDIP_LIST_NIL;
|
|
}
|
|
|
|
const GpObject * GetObject() const
|
|
{
|
|
return ObjectPointer;
|
|
}
|
|
UINT GetUid() const
|
|
{
|
|
return Uid;
|
|
}
|
|
ObjectType GetType() const
|
|
{
|
|
return Type;
|
|
}
|
|
};
|
|
|
|
class MetafileRecordObjectList
|
|
{
|
|
protected:
|
|
INT Count;
|
|
UINT LRU;
|
|
UINT MRU;
|
|
MetafileRecordObject Objects[GDIP_MAX_OBJECTS];
|
|
|
|
public:
|
|
MetafileRecordObjectList()
|
|
{
|
|
Count = 0;
|
|
LRU = GDIP_LIST_NIL;
|
|
MRU = GDIP_LIST_NIL;
|
|
}
|
|
|
|
MetafileRecordObject * GetMetaObject(UINT metaObjectID)
|
|
{
|
|
ASSERT(metaObjectID < GDIP_MAX_OBJECTS);
|
|
return Objects + metaObjectID;
|
|
}
|
|
|
|
// Search through the list, starting at the MRU entry, to see if we
|
|
// can find the object. If we do find it, return the index to the
|
|
// object in metaObjectId (even if the Uid's don't match). Return
|
|
// TRUE only if we found the object and the Uid's match.
|
|
BOOL
|
|
IsInList(
|
|
const GpObject * object,
|
|
ObjectType objectType,
|
|
UINT32 * metaObjectId
|
|
);
|
|
|
|
#if 0 // not used
|
|
VOID
|
|
RemoveAt(
|
|
UINT32 metaObjectId
|
|
);
|
|
#endif
|
|
|
|
// if metaObjectId is GDIP_LIST_NIL, use the next available slot
|
|
VOID
|
|
InsertAt(
|
|
const GpObject * object,
|
|
UINT32 * metaObjectId
|
|
);
|
|
|
|
VOID
|
|
UpdateMRU(
|
|
UINT32 metaObjectId
|
|
);
|
|
};
|
|
|
|
// Search through the list, starting at the MRU entry, to see if we
|
|
// can find the object. If we do find it, return the index to the
|
|
// object in metaObjectId (even if the Uid's don't match). Return
|
|
// TRUE only if we found the object and the Uid's match.
|
|
BOOL
|
|
MetafileRecordObjectList::IsInList(
|
|
const GpObject * object,
|
|
ObjectType objectType,
|
|
UINT32 * metaObjectId
|
|
)
|
|
{
|
|
ASSERT(object != NULL);
|
|
ASSERT(metaObjectId != NULL);
|
|
|
|
BOOL isInList = FALSE;
|
|
|
|
isInList = FALSE; // indicate object not found
|
|
*metaObjectId = GDIP_LIST_NIL; // indicate object not found
|
|
|
|
if (Count != 0)
|
|
{
|
|
UINT curIndex;
|
|
UINT uid;
|
|
|
|
curIndex = MRU;
|
|
uid = object->GetUid();
|
|
|
|
do
|
|
{
|
|
if (Objects[curIndex].ObjectPointer == object)
|
|
{
|
|
*metaObjectId = curIndex;
|
|
isInList = ((Objects[curIndex].Uid == uid) &&
|
|
(Objects[curIndex].Type == objectType));
|
|
break;
|
|
}
|
|
curIndex = Objects[curIndex].Prev;
|
|
} while (curIndex != GDIP_LIST_NIL);
|
|
}
|
|
|
|
return isInList;
|
|
}
|
|
|
|
#if 0 // not used
|
|
// We don't actually remove it from the list, we just put it at the
|
|
// front of the LRU so its spot gets used next. So the count stays
|
|
// the same.
|
|
VOID
|
|
MetafileRecordObjectList::RemoveAt(
|
|
UINT32 metaObjectId
|
|
)
|
|
{
|
|
ASSERT(metaObjectId < GDIP_MAX_OBJECTS);
|
|
|
|
MetafileRecordObject * removeObject = Objects + metaObjectId;
|
|
|
|
ASSERT(Count > 0);
|
|
removeObject->ObjectPointer = NULL;
|
|
removeObject->Uid = 0;
|
|
removeObject->Type = EmfPlusRecordTypeInvalid;
|
|
|
|
INT removeNext = removeObject->Next;
|
|
INT removePrev = removeObject->Prev;
|
|
|
|
if (removeNext != GDIP_LIST_NIL)
|
|
{
|
|
Objects[removeNext].Prev = removePrev;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(MRU == metaObjectId);
|
|
if (removePrev != GDIP_LIST_NIL)
|
|
{
|
|
MRU = removePrev;
|
|
}
|
|
}
|
|
|
|
if (removePrev != GDIP_LIST_NIL)
|
|
{
|
|
ASSERT(LRU != metaObjectId);
|
|
Objects[removePrev].Next = removeNext;
|
|
removeObject->Prev = GDIP_LIST_NIL;
|
|
removeObject->Next = LRU;
|
|
Objects[LRU].Prev = metaObjectId;
|
|
LRU = metaObjectId;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(LRU == metaObjectId);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Make the specified object the MRU object.
|
|
VOID
|
|
MetafileRecordObjectList::UpdateMRU(
|
|
UINT32 metaObjectId
|
|
)
|
|
{
|
|
if (MRU != metaObjectId)
|
|
{
|
|
// Now we know there are at least 2 objects
|
|
MetafileRecordObject * object = &Objects[metaObjectId];
|
|
if (LRU != metaObjectId)
|
|
{
|
|
Objects[object->Prev].Next = object->Next;
|
|
}
|
|
else
|
|
{
|
|
LRU = object->Next;
|
|
}
|
|
Objects[object->Next].Prev = object->Prev;
|
|
object->Prev = MRU;
|
|
object->Next = GDIP_LIST_NIL;
|
|
Objects[MRU].Next = metaObjectId;
|
|
MRU = metaObjectId;
|
|
}
|
|
}
|
|
|
|
// if metaObjectId is GDIP_LIST_NIL, use the next available slot
|
|
VOID
|
|
MetafileRecordObjectList::InsertAt(
|
|
const GpObject * object,
|
|
UINT32 * metaObjectId
|
|
)
|
|
{
|
|
MetafileRecordObject * newObject;
|
|
UINT newIndex = *metaObjectId;
|
|
|
|
if (newIndex == GDIP_LIST_NIL)
|
|
{
|
|
if (Count != 0)
|
|
{
|
|
// use freed object before adding new one
|
|
if ((Objects[LRU].ObjectPointer == NULL) ||
|
|
(Count == GDIP_MAX_OBJECTS))
|
|
{
|
|
newIndex = LRU;
|
|
UseLRU:
|
|
LRU = Objects[newIndex].Next;
|
|
Objects[LRU].Prev = GDIP_LIST_NIL;
|
|
}
|
|
else
|
|
{
|
|
newIndex = Count++;
|
|
}
|
|
InsertObject:
|
|
Objects[MRU].Next = newIndex;
|
|
|
|
SetupObject:
|
|
*metaObjectId = newIndex;
|
|
newObject = &Objects[newIndex];
|
|
newObject->Next = GDIP_LIST_NIL;
|
|
newObject->Prev = MRU;
|
|
MRU = newIndex;
|
|
UseMRU:
|
|
newObject->ObjectPointer = object;
|
|
newObject->Uid = object->GetUid();
|
|
newObject->Type = object->GetObjectType();
|
|
return;
|
|
}
|
|
// else first object
|
|
newIndex = 0;
|
|
LRU = 0;
|
|
Count = 1;
|
|
goto SetupObject;
|
|
}
|
|
else // we already know where to put the object
|
|
{
|
|
ASSERT(Count > 0);
|
|
ASSERT(newIndex < GDIP_MAX_OBJECTS);
|
|
|
|
if (newIndex == MRU)
|
|
{
|
|
// This covers the case where there is only 1 object
|
|
newObject = &Objects[newIndex];
|
|
goto UseMRU;
|
|
}
|
|
// else there must be at least 2 objects
|
|
ASSERT(Count > 1);
|
|
|
|
if (newIndex == LRU)
|
|
{
|
|
goto UseLRU;
|
|
}
|
|
// Move middle object to MRU
|
|
newObject = &Objects[newIndex];
|
|
Objects[newObject->Prev].Next = newObject->Next;
|
|
Objects[newObject->Next].Prev = newObject->Prev;
|
|
goto InsertObject;
|
|
}
|
|
}
|
|
|
|
#define GDIP_MAX_COMMENT_SIZE 65020 // must be <= 65520 for Win9x bug
|
|
|
|
class EmfPlusCommentStream : public IUnknownBase<IStream>
|
|
{
|
|
private:
|
|
ObjectTag Tag; // Keep this as the 1st value in the object!
|
|
|
|
protected:
|
|
VOID SetValid(BOOL valid)
|
|
{
|
|
Tag = valid ? ObjectTagEmfPlusCommentStream : ObjectTagInvalid;
|
|
}
|
|
|
|
public:
|
|
EmfPlusCommentStream(HDC hdc)
|
|
{
|
|
ASSERT(hdc != NULL);
|
|
|
|
MetafileHdc = hdc;
|
|
Position = 0; // starts after signature
|
|
((INT32 *)CommentBuffer)[0] = EMFPLUS_SIGNATURE;
|
|
RecordDataStart = CommentBuffer + sizeof(INT32);
|
|
ContinuingObjectRecord = FALSE;
|
|
SetValid(TRUE);
|
|
}
|
|
|
|
~EmfPlusCommentStream()
|
|
{
|
|
this->Flush();
|
|
}
|
|
|
|
BOOL IsValid() const
|
|
{
|
|
ASSERT((Tag == ObjectTagEmfPlusCommentStream) || (Tag == ObjectTagInvalid));
|
|
return (Tag == ObjectTagEmfPlusCommentStream);
|
|
}
|
|
|
|
ULONG SpaceLeft() const
|
|
{
|
|
return (GDIP_MAX_COMMENT_SIZE - Position);
|
|
}
|
|
|
|
VOID
|
|
EndObjectRecord()
|
|
{
|
|
ASSERT ((Position & 0x03) == 0); // records should be 4-byte aligned
|
|
|
|
if (ContinuingObjectRecord)
|
|
{
|
|
ContinuingObjectRecord = FALSE;
|
|
if (Position > sizeof(EmfPlusContinueObjectRecord))
|
|
{
|
|
// Fix up the size of the last chunck of this object record
|
|
EmfPlusContinueObjectRecord * recordData;
|
|
recordData = (EmfPlusContinueObjectRecord *)RecordDataStart;
|
|
recordData->Size = Position;
|
|
recordData->DataSize = Position - sizeof(EmfPlusRecord);
|
|
}
|
|
else
|
|
{
|
|
// The object record ended exacly at the end of the buffer
|
|
// and has already been flushed.
|
|
Position = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
WriteRecordHeader(
|
|
UINT32 dataSize, // size of data (w/o record header)
|
|
EmfPlusRecordType type,
|
|
INT flags // 16 bits of flags
|
|
);
|
|
|
|
VOID Flush();
|
|
|
|
HRESULT STDMETHODCALLTYPE Write(
|
|
VOID const HUGEP *pv,
|
|
ULONG cb,
|
|
ULONG *pcbWritten)
|
|
{
|
|
if (cb == 0)
|
|
{
|
|
if (pcbWritten != NULL)
|
|
{
|
|
*pcbWritten = cb;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
ASSERT (pv != NULL);
|
|
|
|
if (IsValid())
|
|
{
|
|
// We've already written the record header; now we're writing
|
|
// the record data.
|
|
ASSERT(Position >= sizeof(EmfPlusRecord));
|
|
|
|
ULONG spaceLeft = SpaceLeft();
|
|
BYTE * recordData = RecordDataStart + Position;
|
|
|
|
// We flush as soon as we reach the end. We don't wait for
|
|
// the next write call to flush.
|
|
ASSERT(spaceLeft > 0);
|
|
|
|
if (pcbWritten)
|
|
{
|
|
*pcbWritten = cb;
|
|
}
|
|
|
|
// see if there is enough room for the data
|
|
if (cb <= spaceLeft)
|
|
{
|
|
GpMemcpy(recordData, pv, cb);
|
|
Position += cb;
|
|
|
|
if (Position < GDIP_MAX_COMMENT_SIZE)
|
|
{
|
|
return S_OK;
|
|
}
|
|
this->Flush();
|
|
if (IsValid())
|
|
{
|
|
return S_OK;
|
|
}
|
|
if (pcbWritten)
|
|
{
|
|
*pcbWritten = 0;
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
ASSERT(ContinuingObjectRecord);
|
|
|
|
LoopStart:
|
|
GpMemcpy(recordData, pv, spaceLeft);
|
|
Position += spaceLeft;
|
|
if (Position == GDIP_MAX_COMMENT_SIZE)
|
|
{
|
|
this->Flush();
|
|
if (!IsValid())
|
|
{
|
|
if (pcbWritten)
|
|
{
|
|
*pcbWritten = 0; // not accurate, but who cares!
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
cb -= spaceLeft;
|
|
if (cb == 0)
|
|
{
|
|
return S_OK;
|
|
}
|
|
pv = ((BYTE *)pv) + spaceLeft;
|
|
recordData = RecordDataStart + sizeof(EmfPlusContinueObjectRecord);
|
|
spaceLeft = GDIP_MAX_COMMENT_SIZE-sizeof(EmfPlusContinueObjectRecord);
|
|
if (spaceLeft > cb)
|
|
{
|
|
spaceLeft = cb;
|
|
}
|
|
goto LoopStart;
|
|
}
|
|
return E_FAIL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Read(
|
|
VOID HUGEP *pv,
|
|
ULONG cb,
|
|
ULONG *pcbRead)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Seek(
|
|
LARGE_INTEGER dlibMove,
|
|
DWORD dwOrigin,
|
|
ULARGE_INTEGER *plibNewPosition)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE SetSize(
|
|
ULARGE_INTEGER libNewSize)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CopyTo(
|
|
IStream *pstm,
|
|
ULARGE_INTEGER cb,
|
|
ULARGE_INTEGER *pcbRead,
|
|
ULARGE_INTEGER *pcbWritten)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Commit(
|
|
DWORD grfCommitFlags)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Revert(VOID)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE LockRegion(
|
|
ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE UnlockRegion(
|
|
ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Stat(
|
|
STATSTG *pstatstg,
|
|
DWORD grfStatFlag)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE Clone(
|
|
IStream **ppstm)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
private:
|
|
BYTE CommentBuffer[GDIP_MAX_COMMENT_SIZE + sizeof(INT32)];
|
|
BYTE * RecordDataStart;
|
|
ULONG Position;
|
|
HDC MetafileHdc;
|
|
BOOL ContinuingObjectRecord;
|
|
};
|
|
|
|
VOID
|
|
EmfPlusCommentStream::Flush()
|
|
{
|
|
ASSERT ((Position & 0x03) == 0); // records should be 4-byte aligned
|
|
|
|
if (IsValid() && (Position >= sizeof(EmfPlusRecord)))
|
|
{
|
|
// write the signature as well as the records
|
|
SetValid(GdiComment(MetafileHdc, (INT)Position + sizeof(INT32),
|
|
CommentBuffer) != 0);
|
|
|
|
#if DBG
|
|
if (!IsValid())
|
|
{
|
|
WARNING(("Failed to write GdiComment"));
|
|
}
|
|
#endif
|
|
|
|
if (!ContinuingObjectRecord)
|
|
{
|
|
Position = 0;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(Position == GDIP_MAX_COMMENT_SIZE);
|
|
|
|
// Leave the object record header intact for the rest of the
|
|
// object data.
|
|
Position = sizeof(EmfPlusContinueObjectRecord);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
EmfPlusCommentStream::WriteRecordHeader(
|
|
UINT32 dataSize, // size of data (w/o record header)
|
|
EmfPlusRecordType type,
|
|
INT flags // 16 bits of flags
|
|
)
|
|
{
|
|
ASSERT ((flags & 0xFFFF0000) == 0);
|
|
ASSERT (ContinuingObjectRecord == FALSE);
|
|
ASSERT ((Position & 0x03) == 0); // records should be 4-byte aligned
|
|
ASSERT ((dataSize & 0x03) == 0); // records should be 4-byte aligned
|
|
|
|
if (IsValid())
|
|
{
|
|
ULONG spaceLeft = SpaceLeft();
|
|
ULONG recordSize = sizeof(EmfPlusRecord) + dataSize;
|
|
|
|
ASSERT(spaceLeft > 0);
|
|
|
|
// see if the record fits in the space left
|
|
if (recordSize <= spaceLeft)
|
|
{
|
|
RecordFits:
|
|
EmfPlusRecord * recordData;
|
|
|
|
recordData = (EmfPlusRecord *)(RecordDataStart + Position);
|
|
|
|
recordData->Type = type;
|
|
recordData->Flags = (INT16)flags;
|
|
recordData->Size = recordSize;
|
|
recordData->DataSize = dataSize;
|
|
Position += sizeof(EmfPlusRecord);
|
|
if (Position < GDIP_MAX_COMMENT_SIZE)
|
|
{
|
|
return;
|
|
}
|
|
ASSERT((recordSize == sizeof(EmfPlusRecord)) && (dataSize == 0));
|
|
this->Flush();
|
|
return;
|
|
}
|
|
else // it doesn't fit in the space left
|
|
{
|
|
// maybe it will fit after flushing the current record buffer
|
|
if (spaceLeft < GDIP_MAX_COMMENT_SIZE)
|
|
{
|
|
this->Flush();
|
|
if (!IsValid())
|
|
{
|
|
return;
|
|
}
|
|
if (recordSize <= GDIP_MAX_COMMENT_SIZE)
|
|
{
|
|
goto RecordFits;
|
|
}
|
|
}
|
|
|
|
// Now we know the record does not fit in a single comment.
|
|
// This better be an object record!
|
|
ASSERT(type == EmfPlusRecordTypeObject);
|
|
|
|
flags |= GDIP_EPRFLAGS_CONTINUEOBJECT;
|
|
ContinuingObjectRecord = TRUE;
|
|
|
|
// We know that Position is 0
|
|
EmfPlusContinueObjectRecord * recordData;
|
|
recordData = (EmfPlusContinueObjectRecord *)RecordDataStart;
|
|
|
|
recordData->Type = type;
|
|
recordData->Flags = (INT16)flags;
|
|
recordData->Size = GDIP_MAX_COMMENT_SIZE;
|
|
recordData->DataSize = GDIP_MAX_COMMENT_SIZE - sizeof(EmfPlusRecord);
|
|
recordData->TotalObjectSize = dataSize; // size of object data (w/o header size)
|
|
Position = sizeof(EmfPlusContinueObjectRecord);
|
|
}
|
|
}
|
|
}
|
|
|
|
class MetafileRecorder : public IMetafileRecord
|
|
{
|
|
friend class GpMetafile;
|
|
|
|
private:
|
|
ObjectTag Tag; // Keep this as the 1st value in the object!
|
|
|
|
protected:
|
|
VOID SetValid(BOOL valid)
|
|
{
|
|
Tag = valid ? ObjectTagMetafileRecorder : ObjectTagInvalid;
|
|
}
|
|
|
|
public:
|
|
BOOL WroteFrameRect;
|
|
SIZEL Millimeters;
|
|
|
|
protected:
|
|
EmfPlusCommentStream * EmfPlusStream; // memory buffer stream
|
|
GpMetafile * Metafile; // being recorded
|
|
EmfType Type;
|
|
REAL XMinDevice; // device bounds
|
|
REAL YMinDevice;
|
|
REAL XMaxDevice;
|
|
REAL YMaxDevice;
|
|
BOOL BoundsInit;
|
|
INT NumRecords; // for debugging only
|
|
INT MaxStackSize;
|
|
HDC MetafileHdc;
|
|
DynArrayIA<INT,GDIP_SAVE_STACK_SIZE> SaveRestoreStack;
|
|
MetafileRecordObjectList ObjectList;
|
|
GpRectF MetafileBounds;
|
|
|
|
public:
|
|
MetafileRecorder(
|
|
GpMetafile * metafile,
|
|
EmfType type,
|
|
HDC metafileHdc,
|
|
BOOL wroteFrameRect,
|
|
SIZEL & effectiveMillimeters,
|
|
GpRectF & metafileBounds
|
|
);
|
|
|
|
~MetafileRecorder() // called by EndRecording
|
|
{
|
|
// Release the memory stream for writing the GdiComments
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
EmfPlusStream->Release();
|
|
}
|
|
}
|
|
|
|
BOOL IsValid() const
|
|
{
|
|
ASSERT((Tag == ObjectTagMetafileRecorder) || (Tag == ObjectTagInvalid));
|
|
return (Tag == ObjectTagMetafileRecorder);
|
|
}
|
|
|
|
virtual VOID GetMetafileBounds(GpRect & metafileBounds) const
|
|
{
|
|
// Use Floor to make sure we don't miss any pixels
|
|
metafileBounds.X = GpFloor(MetafileBounds.X);
|
|
metafileBounds.Y = GpFloor(MetafileBounds.Y);
|
|
metafileBounds.Width = GpCeiling(MetafileBounds.GetRight()) - metafileBounds.X;
|
|
metafileBounds.Height = GpCeiling(MetafileBounds.GetBottom()) - metafileBounds.Y;
|
|
}
|
|
|
|
virtual GpStatus
|
|
RecordClear(
|
|
const GpRectF * deviceBounds,
|
|
GpColor color
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordFillRects(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush * brush,
|
|
const GpRectF * rects,
|
|
INT count
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawRects(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpRectF * rects,
|
|
INT count
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordFillPolygon(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush* brush,
|
|
const GpPointF * points,
|
|
INT count,
|
|
GpFillMode fillMode
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawLines(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpPointF * points,
|
|
INT count,
|
|
BOOL closed
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordFillEllipse(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush * brush,
|
|
const GpRectF & rect
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawEllipse(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpRectF & rect
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordFillPie(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush * brush,
|
|
const GpRectF & rect,
|
|
REAL startAngle,
|
|
REAL sweepAngle
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawPie(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpRectF & rect,
|
|
REAL startAngle,
|
|
REAL sweepAngle
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawArc(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpRectF & rect,
|
|
REAL startAngle,
|
|
REAL sweepAngle
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordFillRegion(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush * brush,
|
|
GpRegion * region
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordFillPath(
|
|
const GpRectF * deviceBounds,
|
|
const GpBrush * brush,
|
|
GpPath * path
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawPath(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
GpPath * path
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordFillClosedCurve(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush * brush,
|
|
const GpPointF * points,
|
|
INT count,
|
|
REAL tension,
|
|
GpFillMode fillMode
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawClosedCurve(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpPointF * points,
|
|
INT count,
|
|
REAL tension
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawCurve(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpPointF * points,
|
|
INT count,
|
|
REAL tension,
|
|
INT offset,
|
|
INT numberOfSegments
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawBeziers(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpPointF * points,
|
|
INT count
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawImage(
|
|
const GpRectF * deviceBounds,
|
|
const GpImage * image,
|
|
const GpRectF & destRect,
|
|
const GpRectF & srcRect,
|
|
GpPageUnit srcUnit,
|
|
const GpImageAttributes * imageAttributes
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawImage(
|
|
const GpRectF * deviceBounds,
|
|
const GpImage * image,
|
|
const GpPointF * destPoints,
|
|
INT count,
|
|
const GpRectF & srcRect,
|
|
GpPageUnit srcUnit,
|
|
const GpImageAttributes * imageAttributes
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawString(
|
|
const GpRectF * deviceBounds,
|
|
const WCHAR *string,
|
|
INT length,
|
|
const GpFont *font,
|
|
const RectF *layoutRect,
|
|
const GpStringFormat *format,
|
|
const GpBrush *brush
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordDrawDriverString(
|
|
const GpRectF * deviceBounds,
|
|
const UINT16 *text,
|
|
INT glyphCount,
|
|
const GpFont *font,
|
|
const GpBrush *brush,
|
|
const PointF *positions,
|
|
INT flags,
|
|
const GpMatrix *matrix
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSave(
|
|
INT gstate
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordRestore(
|
|
INT gstate
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordBeginContainer(
|
|
const GpRectF & destRect,
|
|
const GpRectF & srcRect,
|
|
GpPageUnit srcUnit,
|
|
INT containerState
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordBeginContainer(
|
|
INT containerState
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordEndContainer(
|
|
INT containerState
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetWorldTransform(
|
|
const GpMatrix & matrix
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordResetWorldTransform();
|
|
|
|
virtual GpStatus
|
|
RecordMultiplyWorldTransform(
|
|
const GpMatrix & matrix,
|
|
GpMatrixOrder order
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordTranslateWorldTransform(
|
|
REAL dx,
|
|
REAL dy,
|
|
GpMatrixOrder order
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordScaleWorldTransform(
|
|
REAL sx,
|
|
REAL sy,
|
|
GpMatrixOrder order
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordRotateWorldTransform(
|
|
REAL angle,
|
|
GpMatrixOrder order
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetPageTransform(
|
|
GpPageUnit unit,
|
|
REAL scale
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordResetClip();
|
|
|
|
virtual GpStatus
|
|
RecordSetClip(
|
|
const GpRectF & rect,
|
|
CombineMode combineMode
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetClip(
|
|
GpRegion * region,
|
|
CombineMode combineMode
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetClip(
|
|
GpPath * path,
|
|
CombineMode combineMode,
|
|
BOOL isDevicePath
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordOffsetClip(
|
|
REAL dx,
|
|
REAL dy
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordGetDC();
|
|
|
|
virtual GpStatus
|
|
RecordSetAntiAliasMode(
|
|
BOOL newMode
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetTextRenderingHint(
|
|
TextRenderingHint newMode
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetTextContrast(
|
|
UINT gammaValue
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetInterpolationMode(
|
|
InterpolationMode newMode
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetPixelOffsetMode(
|
|
PixelOffsetMode newMode
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetCompositingMode(
|
|
GpCompositingMode newMode
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetCompositingQuality(
|
|
GpCompositingQuality newQuality
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordSetRenderingOrigin(
|
|
INT x,
|
|
INT y
|
|
);
|
|
|
|
virtual GpStatus
|
|
RecordComment(
|
|
UINT sizeData,
|
|
const BYTE * data
|
|
);
|
|
|
|
virtual VOID
|
|
EndRecording();
|
|
|
|
virtual GpStatus
|
|
RecordBackupObject(
|
|
const GpObject * object
|
|
);
|
|
|
|
protected:
|
|
|
|
GpStatus
|
|
RecordHeader(
|
|
INT logicalDpiX,
|
|
INT logicalDpiY,
|
|
INT emfPlusFlags
|
|
);
|
|
VOID RecordEndOfFile();
|
|
|
|
VOID
|
|
WriteObject(
|
|
ObjectType type,
|
|
const GpObject * object,
|
|
UINT32 metaObjectId
|
|
);
|
|
|
|
VOID
|
|
RecordObject(
|
|
const GpObject * object,
|
|
UINT32* metaObjectId
|
|
);
|
|
|
|
GpStatus
|
|
RecordZeroDataRecord(
|
|
EmfPlusRecordType type,
|
|
INT flags
|
|
);
|
|
|
|
VOID
|
|
WriteRecordHeader(
|
|
UINT32 dataSize,
|
|
EmfPlusRecordType type,
|
|
INT flags = 0, // 16 bits of flags
|
|
const GpRectF * deviceBounds = NULL
|
|
);
|
|
|
|
// To keep the number of comments low, this only needs to be called
|
|
// when there is a down-level representation of the GDI+ record.
|
|
VOID
|
|
WriteGdiComment()
|
|
{
|
|
// If we're doing dual (which means we're about to write
|
|
// down-level records) then write out the current list
|
|
// of records in the EmfPlusStream buffer.
|
|
if (Type == EmfTypeEmfPlusDual)
|
|
{
|
|
EmfPlusStream->Flush();
|
|
}
|
|
}
|
|
|
|
VOID
|
|
GetBrushValueForRecording(
|
|
const GpBrush *brush,
|
|
UINT32 &brushValue,
|
|
INT &flags
|
|
);
|
|
};
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Construct a MetafileRecorder object and initialize it.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] metafile - pointer to the metafile object being recorded
|
|
* [IN] stream - the stream being recorded into (if any)
|
|
* [IN] metafileHdc - handle to metafile DC being recorded into (if any)
|
|
* [IN] dpiX - the horizontal DPI
|
|
* [IN] dpiY - the vertical DPI
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
MetafileRecorder::MetafileRecorder(
|
|
GpMetafile * metafile,
|
|
EmfType emfType,
|
|
HDC metafileHdc,
|
|
BOOL wroteFrameRect,
|
|
SIZEL & effectiveMillimeters,
|
|
GpRectF & metafileBounds
|
|
)
|
|
{
|
|
SetValid(FALSE);
|
|
Type = emfType;
|
|
Metafile = metafile;
|
|
WroteFrameRect = wroteFrameRect;
|
|
NumRecords = 0; // currently for debugging only
|
|
MaxStackSize = 0;
|
|
MetafileHdc = metafileHdc;
|
|
XMinDevice = FLT_MAX;
|
|
YMinDevice = FLT_MAX;
|
|
XMaxDevice = -FLT_MAX;
|
|
YMaxDevice = -FLT_MAX;
|
|
BoundsInit = FALSE;
|
|
EmfPlusStream = NULL;
|
|
Millimeters = effectiveMillimeters;
|
|
|
|
// The metafileBounds are used as the bounds for FillRegion
|
|
// calls when the region has infinite bounds, to keep from
|
|
// exploding the bounds of the metafile.
|
|
MetafileBounds = metafileBounds;
|
|
|
|
if (emfType == EmfTypeEmfOnly)
|
|
{
|
|
Metafile->Header.Type = MetafileTypeEmf;
|
|
SetValid(TRUE);
|
|
}
|
|
else
|
|
{
|
|
// gets freed in the destructor
|
|
EmfPlusStream = new EmfPlusCommentStream(metafileHdc);
|
|
|
|
if (EmfPlusStream == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SetValid(TRUE);
|
|
|
|
INT logicalDpiX = GetDeviceCaps(metafileHdc, LOGPIXELSX);
|
|
INT logicalDpiY = GetDeviceCaps(metafileHdc, LOGPIXELSY);
|
|
INT emfPlusFlags = 0;
|
|
|
|
if (GetDeviceCaps(metafileHdc, TECHNOLOGY) == DT_RASDISPLAY)
|
|
{
|
|
emfPlusFlags |= GDIP_EMFPLUSFLAGS_DISPLAY;
|
|
}
|
|
|
|
MetafileHeader * header = &(metafile->Header);
|
|
|
|
header->EmfPlusHeaderSize = sizeof(EmfPlusRecord) + sizeof(EmfPlusHeaderRecord);
|
|
header->LogicalDpiX = logicalDpiX;
|
|
header->LogicalDpiY = logicalDpiY;
|
|
header->EmfPlusFlags = emfPlusFlags;
|
|
if (emfType == EmfTypeEmfPlusOnly)
|
|
{
|
|
header->Type = MetafileTypeEmfPlusOnly;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(emfType == EmfTypeEmfPlusDual);
|
|
header->Type = MetafileTypeEmfPlusDual;
|
|
}
|
|
|
|
if (RecordHeader(logicalDpiX, logicalDpiY, emfPlusFlags) != Ok)
|
|
{
|
|
SetValid(FALSE);
|
|
EmfPlusStream->Release();
|
|
EmfPlusStream = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordClear.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] color - the clear color
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 04/28/2000 AGodfrey
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordClear(
|
|
const GpRectF * deviceBounds,
|
|
GpColor color
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
ASSERT (deviceBounds != NULL);
|
|
|
|
ARGB argbColor = color.GetValue();
|
|
|
|
UINT32 dataSize = sizeof(argbColor);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeClear;
|
|
INT flags = 0;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, argbColor);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write Clear record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordFillRects.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] brush - brush to draw with
|
|
* [IN] rects - rectangles to fill
|
|
* [IN] count - number of rects
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordFillRects(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush * brush,
|
|
const GpRectF * rects,
|
|
INT count
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (brush != NULL) &&
|
|
(rects != NULL) && (count > 0));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafileRectData rectData(rects, count);
|
|
UINT32 brushValue; // Metafile Brush Id or ARGB value
|
|
UINT32 dataSize = sizeof(brushValue) +
|
|
sizeof(UINT32/* count */) +
|
|
rectData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeFillRects;
|
|
INT flags = rectData.GetFlags();
|
|
|
|
GetBrushValueForRecording(brush, brushValue, flags);
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, brushValue);
|
|
WriteInt32(EmfPlusStream, count);
|
|
rectData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write FillRects record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawRects.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] pen - pen to draw with
|
|
* [IN] rects - rectangles to draw
|
|
* [IN] count - number of rects
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawRects(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpRectF * rects,
|
|
INT count
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (pen != NULL) &&
|
|
(rects != NULL) && (count > 0));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafileRectData rectData(rects, count);
|
|
UINT32 metaPenId;
|
|
UINT32 dataSize = sizeof(UINT32/* count */) +
|
|
rectData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawRects;
|
|
INT flags = rectData.GetFlags();
|
|
|
|
RecordObject(pen, &metaPenId);
|
|
ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPenId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, count);
|
|
rectData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawRects record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordFillPolygon.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] brush - brush to draw with
|
|
* [IN] points - polygon points
|
|
* [IN] count - number of points
|
|
* [IN] fillMode - Alternate or Winding
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordFillPolygon(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush* brush,
|
|
const GpPointF * points,
|
|
INT count,
|
|
GpFillMode fillMode
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (brush != NULL) &&
|
|
(points != NULL) && (count > 0));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafilePointData pointData(points, count);
|
|
UINT32 brushValue; // Metafile Brush Id or ARGB value
|
|
UINT32 dataSize = sizeof(brushValue) +
|
|
sizeof(UINT32/* count */) +
|
|
pointData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeFillPolygon;
|
|
INT flags = pointData.GetFlags();
|
|
|
|
GetBrushValueForRecording(brush, brushValue, flags);
|
|
|
|
if (fillMode == FillModeWinding)
|
|
{
|
|
flags |= GDIP_EPRFLAGS_WINDINGFILL;
|
|
}
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, brushValue);
|
|
WriteInt32(EmfPlusStream, count);
|
|
pointData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write FillPolygon record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawLines.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] pen - pen to draw with
|
|
* [IN] points - polyline points
|
|
* [IN] count - number of points
|
|
* [IN] closed - TRUE if closed
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawLines(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpPointF * points,
|
|
INT count,
|
|
BOOL closed
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (pen != NULL) &&
|
|
(points != NULL) && (count > 0));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafilePointData pointData(points, count);
|
|
UINT32 metaPenId;
|
|
UINT32 dataSize = sizeof(UINT32/* count */) +
|
|
pointData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawLines;
|
|
INT flags = pointData.GetFlags();
|
|
|
|
RecordObject(pen, &metaPenId);
|
|
ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPenId;
|
|
|
|
if (closed)
|
|
{
|
|
flags |= GDIP_EPRFLAGS_CLOSED;
|
|
}
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, count);
|
|
pointData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawLines record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordFillEllipse.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] brush - brush to draw with
|
|
* [IN] rect - bounding rect of ellipse
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordFillEllipse(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush * brush,
|
|
const GpRectF & rect
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (brush != NULL));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafileRectData rectData(&rect, 1);
|
|
UINT32 brushValue; // Metafile Brush Id or ARGB value
|
|
UINT32 dataSize = sizeof(brushValue) +
|
|
rectData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeFillEllipse;
|
|
INT flags = rectData.GetFlags();
|
|
|
|
GetBrushValueForRecording(brush, brushValue, flags);
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, brushValue);
|
|
rectData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write FillEllipse record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawEllipse.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] pen - pen to draw with
|
|
* [IN] rect - bounding rect of ellipse
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawEllipse(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpRectF & rect
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (pen != NULL));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafileRectData rectData(&rect, 1);
|
|
UINT32 metaPenId;
|
|
UINT32 dataSize = rectData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawEllipse;
|
|
INT flags = rectData.GetFlags();
|
|
|
|
RecordObject(pen, &metaPenId);
|
|
ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPenId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
rectData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawEllipse record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordFillPie.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] brush - brush to draw with
|
|
* [IN] rect - bounding rect of ellipse
|
|
* [IN] startAngle - starting angle of pie
|
|
* [IN] sweepAngle - sweep angle of pie
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordFillPie(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush * brush,
|
|
const GpRectF & rect,
|
|
REAL startAngle,
|
|
REAL sweepAngle
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (brush != NULL));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafileRectData rectData(&rect, 1);
|
|
UINT32 brushValue; // Metafile Brush Id or ARGB value
|
|
UINT32 dataSize = sizeof(brushValue) +
|
|
sizeof(startAngle) +
|
|
sizeof(sweepAngle) +
|
|
rectData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeFillPie;
|
|
INT flags = rectData.GetFlags();
|
|
|
|
GetBrushValueForRecording(brush, brushValue, flags);
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, brushValue);
|
|
WriteReal (EmfPlusStream, startAngle);
|
|
WriteReal (EmfPlusStream, sweepAngle);
|
|
rectData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write FillPie record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawPie.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] pen - pen to draw with
|
|
* [IN] rect - bounding rect of ellipse
|
|
* [IN] startAngle - starting angle of pie
|
|
* [IN] sweepAngle - sweep angle of pie
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawPie(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpRectF & rect,
|
|
REAL startAngle,
|
|
REAL sweepAngle
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (pen != NULL));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafileRectData rectData(&rect, 1);
|
|
UINT32 metaPenId;
|
|
UINT32 dataSize = sizeof(startAngle) +
|
|
sizeof(sweepAngle) +
|
|
rectData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawPie;
|
|
INT flags = rectData.GetFlags();
|
|
|
|
RecordObject(pen, &metaPenId);
|
|
ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPenId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteReal (EmfPlusStream, startAngle);
|
|
WriteReal (EmfPlusStream, sweepAngle);
|
|
rectData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawPie record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawArc.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] pen - pen to draw with
|
|
* [IN] rect - bounding rect of ellipse
|
|
* [IN] startAngle - starting angle of arc
|
|
* [IN] sweepAngle - sweep angle of arc
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawArc(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpRectF & rect,
|
|
REAL startAngle,
|
|
REAL sweepAngle
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (pen != NULL));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafileRectData rectData(&rect, 1);
|
|
UINT32 metaPenId;
|
|
UINT32 dataSize = sizeof(startAngle) +
|
|
sizeof(sweepAngle) +
|
|
rectData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawArc;
|
|
INT flags = rectData.GetFlags();
|
|
|
|
RecordObject(pen, &metaPenId);
|
|
ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPenId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteReal (EmfPlusStream, startAngle);
|
|
WriteReal (EmfPlusStream, sweepAngle);
|
|
rectData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawArc record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordFillRegion.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] brush - brush to draw with
|
|
* [IN] region - region to fill
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordFillRegion(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush * brush,
|
|
GpRegion * region
|
|
)
|
|
{
|
|
// The deviceBounds should never be infinite, because they are
|
|
// intersected with the metafileBounds before being passed in.
|
|
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (brush != NULL) && (region != NULL));
|
|
|
|
if (IsValid())
|
|
{
|
|
UINT32 metaRegionId;
|
|
UINT32 brushValue; // Metafile Brush Id or ARGB value
|
|
UINT32 dataSize = sizeof(brushValue);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeFillRegion;
|
|
INT flags = 0;
|
|
|
|
GetBrushValueForRecording(brush, brushValue, flags);
|
|
|
|
RecordObject(region, &metaRegionId);
|
|
ASSERT((metaRegionId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaRegionId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, brushValue);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write FillRegion record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordFillPath.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] brush - brush to draw with
|
|
* [IN] path - path to fill
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordFillPath(
|
|
const GpRectF * deviceBounds,
|
|
const GpBrush * brush,
|
|
GpPath * path
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (brush != NULL) && (path != NULL));
|
|
|
|
if (IsValid())
|
|
{
|
|
UINT32 metaPathId;
|
|
UINT32 brushValue; // Metafile Brush Id or ARGB value
|
|
UINT32 dataSize = sizeof(brushValue);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeFillPath;
|
|
INT flags = 0;
|
|
|
|
GetBrushValueForRecording(brush, brushValue, flags);
|
|
|
|
RecordObject(path, &metaPathId);
|
|
ASSERT((metaPathId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPathId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, brushValue);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write FillPath record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawPath.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] pen - pen to draw with
|
|
* [IN] path - path to draw
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawPath(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
GpPath * path
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (pen != NULL) && (path != NULL));
|
|
|
|
if (IsValid())
|
|
{
|
|
UINT32 metaPathId;
|
|
UINT32 metaPenId;
|
|
UINT32 dataSize = sizeof(metaPenId);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawPath;
|
|
INT flags = 0;
|
|
|
|
RecordObject(pen, &metaPenId);
|
|
|
|
RecordObject(path, &metaPathId);
|
|
ASSERT((metaPathId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPathId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, metaPenId);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawPath record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordFillClosedCurve.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] brush - brush to draw with
|
|
* [IN] points - curve points
|
|
* [IN] count - number of points
|
|
* [IN] tension - how tight to make curve
|
|
* [IN] fillMode - Alternate or Winding
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordFillClosedCurve(
|
|
const GpRectF * deviceBounds,
|
|
GpBrush * brush,
|
|
const GpPointF * points,
|
|
INT count,
|
|
REAL tension,
|
|
GpFillMode fillMode
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (brush != NULL) &&
|
|
(points != NULL) && (count > 0));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafilePointData pointData(points, count);
|
|
UINT32 brushValue; // Metafile Brush Id or ARGB value
|
|
UINT32 dataSize = sizeof(brushValue) +
|
|
sizeof(tension) +
|
|
sizeof(UINT32 /* count */) +
|
|
pointData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeFillClosedCurve;
|
|
INT flags = pointData.GetFlags();
|
|
|
|
GetBrushValueForRecording(brush, brushValue, flags);
|
|
|
|
if (fillMode == FillModeWinding)
|
|
{
|
|
flags |= GDIP_EPRFLAGS_WINDINGFILL;
|
|
}
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, brushValue);
|
|
WriteReal (EmfPlusStream, tension);
|
|
WriteInt32(EmfPlusStream, count);
|
|
pointData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write FillClosedCurve record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawClosedCurve.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] pen - pen to draw with
|
|
* [IN] points - curve points
|
|
* [IN] count - number of points
|
|
* [IN] tension - how tight to make curve
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawClosedCurve(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpPointF * points,
|
|
INT count,
|
|
REAL tension
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (pen != NULL) &&
|
|
(points != NULL) && (count > 0));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafilePointData pointData(points, count);
|
|
UINT32 metaPenId;
|
|
UINT32 dataSize = sizeof(tension) +
|
|
sizeof(UINT32/* count */) +
|
|
pointData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawClosedCurve;
|
|
INT flags = pointData.GetFlags();
|
|
|
|
RecordObject(pen, &metaPenId);
|
|
ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPenId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteReal (EmfPlusStream, tension);
|
|
WriteInt32(EmfPlusStream, count);
|
|
pointData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawClosedCurve record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawCurve.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] pen - pen to draw with
|
|
* [IN] points - curve points
|
|
* [IN] count - number of points
|
|
* [IN] tension - how tight to make curve
|
|
* [IN] offset - offset
|
|
* [IN] numberOfSegments - number of segments
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawCurve(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpPointF * points,
|
|
INT count,
|
|
REAL tension,
|
|
INT offset,
|
|
INT numberOfSegments
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (pen != NULL) &&
|
|
(points != NULL) && (count > 0));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafilePointData pointData(points, count);
|
|
UINT32 metaPenId;
|
|
UINT32 dataSize = sizeof(tension) +
|
|
sizeof(INT32 /* offset */) +
|
|
sizeof(UINT32/* numberOfSegments */) +
|
|
sizeof(UINT32/* count */) +
|
|
pointData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawCurve;
|
|
INT flags = pointData.GetFlags();
|
|
|
|
RecordObject(pen, &metaPenId);
|
|
ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPenId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteReal (EmfPlusStream, tension);
|
|
WriteInt32(EmfPlusStream, offset);
|
|
WriteInt32(EmfPlusStream, numberOfSegments);
|
|
WriteInt32(EmfPlusStream, count);
|
|
pointData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawCurve record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawBeziers.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] pen - pen to draw with
|
|
* [IN] points - curve points
|
|
* [IN] count - number of points
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawBeziers(
|
|
const GpRectF * deviceBounds,
|
|
GpPen * pen,
|
|
const GpPointF * points,
|
|
INT count
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (pen != NULL) &&
|
|
(points != NULL) && (count > 0));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafilePointData pointData(points, count);
|
|
UINT32 metaPenId;
|
|
UINT32 dataSize = sizeof(UINT32/* count */) +
|
|
pointData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawBeziers;
|
|
INT flags = pointData.GetFlags();
|
|
|
|
RecordObject(pen, &metaPenId);
|
|
ASSERT((metaPenId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPenId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, count);
|
|
pointData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawBeziers record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawImage.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] image - image to draw
|
|
* [IN] destRect - where to draw image
|
|
* [IN] srcRect - portion of image to draw
|
|
* [IN] srcUnit - units of srcRect
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawImage(
|
|
const GpRectF * deviceBounds,
|
|
const GpImage * image,
|
|
const GpRectF & destRect,
|
|
const GpRectF & srcRect,
|
|
GpPageUnit srcUnit,
|
|
const GpImageAttributes * imageAttributes
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (image != NULL));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafileRectData rectData(&destRect, 1);
|
|
UINT32 metaImageId;
|
|
UINT32 metaImageAttributesId;
|
|
|
|
UINT32 dataSize = sizeof(INT32) + /* metaImageAttributesId*/
|
|
sizeof(INT32) + /* srcUnit */
|
|
sizeof(srcRect) +
|
|
rectData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawImage;
|
|
INT flags = rectData.GetFlags();
|
|
|
|
RecordObject(image, &metaImageId);
|
|
ASSERT((metaImageId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaImageId;
|
|
|
|
// Record the imageAttributes;
|
|
// imageAttributes can be NULL
|
|
|
|
RecordObject(imageAttributes, &metaImageAttributesId);
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, metaImageAttributesId);
|
|
WriteInt32(EmfPlusStream, srcUnit);
|
|
WriteRect (EmfPlusStream, srcRect);
|
|
rectData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawImage record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawImage.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] deviceBounds - the bounding rect, in device units
|
|
* [IN] image - image to draw
|
|
* [IN] destPoints - where to draw image
|
|
* [IN] count - number of destPoints
|
|
* [IN] srcRect - portion of image to draw
|
|
* [IN] srcUnit - units of srcRect
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawImage(
|
|
const GpRectF * deviceBounds,
|
|
const GpImage * image,
|
|
const GpPointF * destPoints,
|
|
INT count,
|
|
const GpRectF & srcRect,
|
|
GpPageUnit srcUnit,
|
|
const GpImageAttributes * imageAttributes
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT ((deviceBounds != NULL) && (image != NULL) &&
|
|
(destPoints != NULL) && (count > 0));
|
|
|
|
if (IsValid())
|
|
{
|
|
MetafilePointData pointData(destPoints, count);
|
|
UINT32 metaImageId;
|
|
UINT32 metaImageAttributesId;
|
|
|
|
UINT32 dataSize = sizeof(INT32) + /* metaImageAttributesId*/
|
|
sizeof(INT32) + /* srcUnit */
|
|
sizeof(srcRect) +
|
|
sizeof(UINT32) + /* count */
|
|
pointData.GetDataSize();
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawImagePoints;
|
|
INT flags = pointData.GetFlags();
|
|
|
|
RecordObject(image, &metaImageId);
|
|
ASSERT((metaImageId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaImageId;
|
|
|
|
// Record the imageAttributes;
|
|
// imageAttributes can be NULL
|
|
|
|
RecordObject(imageAttributes, &metaImageAttributesId);
|
|
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, metaImageAttributesId);
|
|
WriteInt32(EmfPlusStream, srcUnit);
|
|
WriteRect (EmfPlusStream, srcRect);
|
|
WriteInt32(EmfPlusStream, count);
|
|
pointData.WriteData(EmfPlusStream);
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawImagePoints record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawString.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] string - string to draw
|
|
* [IN] length - length of string
|
|
* [IN] font - font to use when drawing string
|
|
* [IN] layoutRect - where to draw the string
|
|
* [IN] format - format
|
|
* [IN] brush - brush to draw with
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawString(
|
|
const GpRectF * deviceBounds,
|
|
const WCHAR *string,
|
|
INT length,
|
|
const GpFont *font,
|
|
const RectF *layoutRect,
|
|
const GpStringFormat *format,
|
|
const GpBrush *brush
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT (string && font && brush && layoutRect);
|
|
|
|
if (length < 0)
|
|
{
|
|
if (length == -1)
|
|
{
|
|
length = 0;
|
|
while (string[length] && (length < INT_MAX))
|
|
{
|
|
length++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return InvalidParameter;
|
|
}
|
|
}
|
|
|
|
ASSERT (length > 0);
|
|
|
|
if (IsValid())
|
|
{
|
|
const BYTE * strData = (BYTE *)string; // BYTE or WCHAR
|
|
INT sizeString = length * sizeof(WCHAR);
|
|
INT flags = 0;
|
|
|
|
// !!! TODO:
|
|
// Compress the Unicode string.
|
|
// Use the GDIP_EPRFLAGS_COMPRESSED to indicate that
|
|
// the string has been compressed to ANSI.
|
|
|
|
UINT32 metaFontId;
|
|
UINT32 metaFormatId;
|
|
UINT32 brushValue; // Metafile Brush Id or ARGB value
|
|
UINT32 dataSize = sizeof(brushValue) +
|
|
sizeof(metaFormatId) +
|
|
sizeof(INT32 /* len */) +
|
|
sizeof(*layoutRect) +
|
|
sizeString;
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawString;
|
|
|
|
dataSize = (dataSize + 3) & (~3); // align
|
|
|
|
RecordObject(font, &metaFontId);
|
|
ASSERT((metaFontId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaFontId;
|
|
|
|
// the format can be NULL
|
|
RecordObject(format, &metaFormatId);
|
|
|
|
GetBrushValueForRecording(brush, brushValue, flags);
|
|
WriteRecordHeader(dataSize, type, flags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, brushValue);
|
|
WriteInt32(EmfPlusStream, metaFormatId);
|
|
WriteInt32(EmfPlusStream, length);
|
|
WriteRect (EmfPlusStream, *layoutRect);
|
|
WriteBytes(EmfPlusStream, strData, sizeString);
|
|
|
|
// align
|
|
if ((length & 0x01) != 0)
|
|
{
|
|
length = 0;
|
|
EmfPlusStream->Write(&length, sizeof(WCHAR), NULL);
|
|
}
|
|
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawString record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordDrawdriverString.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] text - string/glyphs
|
|
* [IN] glyphCount - string length
|
|
* [IN] font - font to use when drawing string
|
|
* [IN] brush - brush to draw with
|
|
* [IN] positions - character/glyphs origins
|
|
* [IN] flags - API flags
|
|
* [IN] matrix - transofrmation matrix
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 7/11/2000 Tarekms
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordDrawDriverString(
|
|
const GpRectF *deviceBounds,
|
|
const UINT16 *text,
|
|
INT glyphCount,
|
|
const GpFont *font,
|
|
const GpBrush *brush,
|
|
const PointF *positions,
|
|
INT flags,
|
|
const GpMatrix *matrix
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
ASSERT (text && font && brush && positions);
|
|
|
|
if (glyphCount <= 0)
|
|
{
|
|
return InvalidParameter;
|
|
}
|
|
|
|
if (IsValid())
|
|
{
|
|
const BYTE * textData = (BYTE *)text;
|
|
const BYTE * positionData = (BYTE *)positions;
|
|
INT sizeText = glyphCount * sizeof(UINT16);
|
|
INT sizePositions = glyphCount * sizeof(PointF);
|
|
INT metaFlags = 0;
|
|
|
|
UINT32 metaFontId;
|
|
UINT32 brushValue; // Metafile Brush Id or ARGB value
|
|
UINT32 matrixPresent;
|
|
UINT32 dataSize = sizeof(brushValue) + // brush value
|
|
sizeof(flags) + // API flags
|
|
sizeof(matrixPresent)+ // matix prensences
|
|
sizeof(UINT32) + // glyphCoumt
|
|
sizeText + // Text
|
|
sizePositions; // Positions
|
|
if (matrix == NULL)
|
|
{
|
|
matrixPresent = 0;
|
|
}
|
|
else
|
|
{
|
|
matrixPresent = 1;
|
|
dataSize += GDIP_MATRIX_SIZE;
|
|
}
|
|
|
|
EmfPlusRecordType type = EmfPlusRecordTypeDrawDriverString;
|
|
|
|
dataSize = (dataSize + 3) & (~3); // align
|
|
|
|
RecordObject(font, &metaFontId);
|
|
ASSERT((metaFontId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
metaFlags |= metaFontId;
|
|
|
|
GetBrushValueForRecording(brush, brushValue, metaFlags);
|
|
WriteRecordHeader(dataSize, type, metaFlags, deviceBounds);
|
|
WriteInt32(EmfPlusStream, brushValue);
|
|
WriteInt32(EmfPlusStream, flags);
|
|
WriteInt32(EmfPlusStream, matrixPresent);
|
|
WriteInt32(EmfPlusStream, glyphCount);
|
|
WriteBytes(EmfPlusStream, textData, sizeText);
|
|
WriteBytes(EmfPlusStream, positionData, sizePositions);
|
|
|
|
if (matrix != NULL)
|
|
{
|
|
WriteMatrix(EmfPlusStream, *matrix);
|
|
}
|
|
|
|
// align
|
|
if ((glyphCount & 0x01) != 0)
|
|
{
|
|
sizeText = 0;
|
|
EmfPlusStream->Write(&sizeText, sizeof(WCHAR), NULL);
|
|
}
|
|
|
|
WriteGdiComment(); // is down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write DrawDriverString record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSave.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] gstate - the pushed state (restore to state before this)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSave(
|
|
INT gstate
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = sizeof(UINT32/* index */);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeSave;
|
|
INT index = SaveRestoreStack.GetCount();
|
|
|
|
SaveRestoreStack.Add(gstate);
|
|
|
|
WriteRecordHeader(dataSize, type);
|
|
WriteInt32(EmfPlusStream, index);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write Save record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordRestore.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] gstate - the pushed state (restore to state before this)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordRestore(
|
|
INT gstate
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
INT count = SaveRestoreStack.GetCount();
|
|
INT * stack = SaveRestoreStack.GetDataBuffer();
|
|
|
|
if ((count > 0) && (stack != NULL))
|
|
{
|
|
UINT32 dataSize = sizeof(UINT32/* index */);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeRestore;
|
|
|
|
do
|
|
{
|
|
if (stack[--count] == gstate)
|
|
{
|
|
SaveRestoreStack.SetCount(count);
|
|
WriteRecordHeader(dataSize, type);
|
|
WriteInt32(EmfPlusStream, count);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
break;
|
|
}
|
|
} while (count > 0);
|
|
}
|
|
}
|
|
WARNING(("Failed to write Restore record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordBeginContainer.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] destRect - rect to draw container inside of
|
|
* [IN] srcRect - maps source size to destRect
|
|
* [IN] srcUnit - units of srcRect
|
|
* [IN] containerState - the pushed state (restore to state before this)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordBeginContainer(
|
|
const GpRectF & destRect,
|
|
const GpRectF & srcRect,
|
|
GpPageUnit srcUnit,
|
|
INT containerState
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = GDIP_RECTF_SIZE /* destRect */ +
|
|
GDIP_RECTF_SIZE /* srcRect */ +
|
|
sizeof(UINT32/* index */);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeBeginContainer;
|
|
INT index = SaveRestoreStack.GetCount();
|
|
INT flags = srcUnit;
|
|
|
|
ASSERT((flags & (~GDIP_EPRFLAGS_PAGEUNIT)) == 0);
|
|
|
|
if (index >= MaxStackSize)
|
|
{
|
|
MaxStackSize = index + 1;
|
|
}
|
|
|
|
SaveRestoreStack.Add(containerState);
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
WriteRect(EmfPlusStream, destRect);
|
|
WriteRect(EmfPlusStream, srcRect);
|
|
WriteInt32(EmfPlusStream, index);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write BeginContainer record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordBeginContainer.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] containerState - the pushed state (restore to state before this)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordBeginContainer(
|
|
INT containerState
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = sizeof(UINT32/* index */);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeBeginContainerNoParams;
|
|
INT index = SaveRestoreStack.GetCount();
|
|
INT flags = 0;
|
|
|
|
if (index >= MaxStackSize)
|
|
{
|
|
MaxStackSize = index + 1;
|
|
}
|
|
|
|
SaveRestoreStack.Add(containerState);
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
WriteInt32(EmfPlusStream, index);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write BeginContainer record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordEndContainer.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] containerState - the pushed state (restore to state before this)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordEndContainer(
|
|
INT containerState
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
INT count = SaveRestoreStack.GetCount();
|
|
INT * stack = SaveRestoreStack.GetDataBuffer();
|
|
|
|
if ((count > 0) && (stack != NULL))
|
|
{
|
|
UINT32 dataSize = sizeof(UINT32/* index */);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeEndContainer;
|
|
|
|
do
|
|
{
|
|
if (stack[--count] == containerState)
|
|
{
|
|
SaveRestoreStack.SetCount(count);
|
|
WriteRecordHeader(dataSize, type);
|
|
WriteInt32(EmfPlusStream, count);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
break;
|
|
}
|
|
} while (count > 0);
|
|
}
|
|
}
|
|
WARNING(("Failed to write EndContainer record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetWorldTransform.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] matrix - matrix to set in graphics
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetWorldTransform(
|
|
const GpMatrix & matrix
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = GDIP_MATRIX_SIZE;
|
|
EmfPlusRecordType type = EmfPlusRecordTypeSetWorldTransform;
|
|
|
|
WriteRecordHeader(dataSize, type);
|
|
WriteMatrix(EmfPlusStream, matrix);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write SetWorldTransform record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordResetWorldTransform.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* NONE
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordResetWorldTransform()
|
|
{
|
|
return RecordZeroDataRecord(EmfPlusRecordTypeResetWorldTransform, 0);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordMultiplyWorldTransform.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] matrix - matrix to set in graphics
|
|
* [IN] order - Append or Prepend
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordMultiplyWorldTransform(
|
|
const GpMatrix & matrix,
|
|
GpMatrixOrder order
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = GDIP_MATRIX_SIZE;
|
|
EmfPlusRecordType type = EmfPlusRecordTypeMultiplyWorldTransform;
|
|
INT flags = 0;
|
|
|
|
if (order == MatrixOrderAppend)
|
|
{
|
|
flags |= GDIP_EPRFLAGS_APPEND;
|
|
}
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
WriteMatrix(EmfPlusStream, matrix);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write MultiplyWorldTransform record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordTranslateWorldTransform.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] dx - x translation
|
|
* [IN] dy - y translation
|
|
* [IN] order - Append or Prepend
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordTranslateWorldTransform(
|
|
REAL dx,
|
|
REAL dy,
|
|
GpMatrixOrder order
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = sizeof(dx) + sizeof(dy);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeTranslateWorldTransform;
|
|
INT flags = 0;
|
|
|
|
if (order == MatrixOrderAppend)
|
|
{
|
|
flags |= GDIP_EPRFLAGS_APPEND;
|
|
}
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
WriteReal(EmfPlusStream, dx);
|
|
WriteReal(EmfPlusStream, dy);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write TranslateWorldTransform record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordScaleWorldTransform.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] sx - x scale
|
|
* [IN] sy - y scale
|
|
* [IN] order - Append or Prepend
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordScaleWorldTransform(
|
|
REAL sx,
|
|
REAL sy,
|
|
GpMatrixOrder order
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = sizeof(sx) + sizeof(sy);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeScaleWorldTransform;
|
|
INT flags = 0;
|
|
|
|
if (order == MatrixOrderAppend)
|
|
{
|
|
flags |= GDIP_EPRFLAGS_APPEND;
|
|
}
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
WriteReal(EmfPlusStream, sx);
|
|
WriteReal(EmfPlusStream, sy);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write ScaleWorldTransform record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordRotateWorldTransform.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] angle - rotation angle
|
|
* [IN] order - Append or Prepend
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordRotateWorldTransform(
|
|
REAL angle,
|
|
GpMatrixOrder order
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = sizeof(angle);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeRotateWorldTransform;
|
|
INT flags = 0;
|
|
|
|
if (order == MatrixOrderAppend)
|
|
{
|
|
flags |= GDIP_EPRFLAGS_APPEND;
|
|
}
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
WriteReal(EmfPlusStream, angle);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write RotateWorldTransform record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetPageTransform.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] unit - units to use
|
|
* [IN] scale - scale factor to apply
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetPageTransform(
|
|
GpPageUnit unit,
|
|
REAL scale
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = sizeof(scale);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeSetPageTransform;
|
|
INT flags = unit;
|
|
|
|
ASSERT((flags & (~GDIP_EPRFLAGS_PAGEUNIT)) == 0);
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
WriteReal(EmfPlusStream, scale);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write SetPageTransform record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordResetClip.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* NONE
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordResetClip()
|
|
{
|
|
return RecordZeroDataRecord(EmfPlusRecordTypeResetClip, 0);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetClip.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] rect - set clipping to this rect
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetClip(
|
|
const GpRectF & rect,
|
|
CombineMode combineMode
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = GDIP_RECTF_SIZE;
|
|
EmfPlusRecordType type = EmfPlusRecordTypeSetClipRect;
|
|
INT flags = (combineMode << 8);
|
|
|
|
ASSERT((flags & (~GDIP_EPRFLAGS_COMBINEMODE)) == 0);
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
WriteRect(EmfPlusStream, rect);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write SetClipRect record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetClip.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] region - set clipping to this region
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetClip(
|
|
GpRegion * region,
|
|
CombineMode combineMode
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = 0;
|
|
EmfPlusRecordType type = EmfPlusRecordTypeSetClipRegion;
|
|
INT flags = (combineMode << 8);
|
|
UINT32 metaRegionId;
|
|
|
|
ASSERT((flags & (~GDIP_EPRFLAGS_COMBINEMODE)) == 0);
|
|
|
|
RecordObject(region, &metaRegionId);
|
|
ASSERT((metaRegionId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaRegionId;
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write SetClipRegion record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetClip.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] path - set clipping to this path
|
|
* [IN] combineMode - the combine operator (and, or, xor, exclude, complement)
|
|
* [IN] isDevicePath- if path is already in device units
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetClip(
|
|
GpPath * path,
|
|
CombineMode combineMode,
|
|
BOOL isDevicePath
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = 0;
|
|
EmfPlusRecordType type = EmfPlusRecordTypeSetClipPath;
|
|
INT flags = (combineMode << 8);
|
|
UINT32 metaPathId;
|
|
|
|
ASSERT((flags & (~GDIP_EPRFLAGS_COMBINEMODE)) == 0);
|
|
|
|
RecordObject(path, &metaPathId);
|
|
ASSERT((metaPathId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
flags |= metaPathId;
|
|
|
|
if (isDevicePath)
|
|
{
|
|
flags |= GDIP_EPRFLAGS_ISDEVICEPATH;
|
|
}
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write SetClipPath record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordOffsetClip.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] dx - x translation amount
|
|
* [IN] dy - y translation amount
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordOffsetClip(
|
|
REAL dx,
|
|
REAL dy
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = sizeof(dx) + sizeof(dy);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeOffsetClip;
|
|
|
|
WriteRecordHeader(dataSize, type);
|
|
WriteReal(EmfPlusStream, dx);
|
|
WriteReal(EmfPlusStream, dy);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write OffsetClip record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordGetDC.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* NONE
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordGetDC()
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
GpStatus status = RecordZeroDataRecord(EmfPlusRecordTypeGetDC, 0);
|
|
// WriteGdiComment(); // is down-level for this record
|
|
// WriteGdiComment will only flush if writing EMF+ dual,
|
|
// but for EMF+-only, we also have to flush GetDC records!
|
|
EmfPlusStream->Flush();
|
|
return status;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
// Write a record with no data besides the EMF+ record header
|
|
GpStatus
|
|
MetafileRecorder::RecordZeroDataRecord(
|
|
EmfPlusRecordType type,
|
|
INT flags
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = 0;
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetAntiAliasMode.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] newMode - new anti aliasing mode
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetAntiAliasMode(
|
|
BOOL newMode
|
|
)
|
|
{
|
|
return RecordZeroDataRecord(EmfPlusRecordTypeSetAntiAliasMode,
|
|
newMode ? GDIP_EPRFLAGS_ANTIALIAS : 0);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetTextRenderingHint.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] newMode - new rendering hint
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetTextRenderingHint(
|
|
TextRenderingHint newMode
|
|
)
|
|
{
|
|
ASSERT ((newMode & (~GDIP_EPRFLAGS_TEXTRENDERINGHINT)) == 0);
|
|
return RecordZeroDataRecord(EmfPlusRecordTypeSetTextRenderingHint, newMode);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetTextContrast.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] gammaValue - new contrast value
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetTextContrast(
|
|
UINT contrast
|
|
)
|
|
{
|
|
ASSERT ((contrast & (~GDIP_EPRFLAGS_CONTRAST)) == 0);
|
|
return RecordZeroDataRecord(EmfPlusRecordTypeSetTextContrast, contrast);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetInterpolationMode.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] newMode - new interpolation mode
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 5/1/2000 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetInterpolationMode(
|
|
InterpolationMode newMode
|
|
)
|
|
{
|
|
ASSERT ((newMode & (~GDIP_EPRFLAGS_INTERPOLATIONMODE)) == 0);
|
|
return RecordZeroDataRecord(EmfPlusRecordTypeSetInterpolationMode, newMode);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetPixelOffsetMode.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] newMode - new pixel offset mode
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 5/1/2000 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetPixelOffsetMode(
|
|
PixelOffsetMode newMode
|
|
)
|
|
{
|
|
ASSERT ((newMode & (~GDIP_EPRFLAGS_PIXELOFFSETMODE)) == 0);
|
|
return RecordZeroDataRecord(EmfPlusRecordTypeSetPixelOffsetMode, newMode);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetRenderingOrigin.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] x, y - new rendering origin
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 5/4/2000 asecchia
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetRenderingOrigin(
|
|
INT x,
|
|
INT y
|
|
)
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
if (IsValid())
|
|
{
|
|
UINT32 dataSize = sizeof(x) + sizeof(y);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeSetRenderingOrigin;
|
|
|
|
WriteRecordHeader(dataSize, type);
|
|
WriteInt32(EmfPlusStream, x);
|
|
WriteInt32(EmfPlusStream, y);
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
WARNING(("Failed to write SetRenderingOrigin record"));
|
|
return Win32Error;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetCompositingMode.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] newMode - new compositing mode
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 10/11/1999 AGodfrey
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetCompositingMode(
|
|
GpCompositingMode newMode
|
|
)
|
|
{
|
|
ASSERT ((newMode & (~GDIP_EPRFLAGS_COMPOSITINGMODE)) == 0);
|
|
return RecordZeroDataRecord(EmfPlusRecordTypeSetCompositingMode, newMode);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordSetCompositingQuality.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] newQuality - new quality setting
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 04/22/2000 AGodfrey
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordSetCompositingQuality(
|
|
GpCompositingQuality newQuality
|
|
)
|
|
{
|
|
ASSERT ((newQuality & (~GDIP_EPRFLAGS_COMPOSITINGQUALITY)) == 0);
|
|
return RecordZeroDataRecord(EmfPlusRecordTypeSetCompositingQuality, newQuality);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - RecordComment.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] sizeData - number of bytes of data
|
|
* [IN] data - pointer to the data
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/29/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpStatus
|
|
MetafileRecorder::RecordComment(
|
|
UINT sizeData,
|
|
const BYTE * data
|
|
)
|
|
{
|
|
if (IsValid() && (sizeData > 0) && (data != NULL))
|
|
{
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
UINT32 dataSize = (sizeData + 3) & (~3);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeComment;
|
|
INT pad = dataSize - sizeData;
|
|
INT flags = pad;
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
WriteBytes(EmfPlusStream, data, sizeData);
|
|
while(pad--)
|
|
{
|
|
WriteByte(EmfPlusStream, 0);
|
|
}
|
|
// WriteGdiComment(); no down-level for this record
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
}
|
|
else if (Type == EmfTypeEmfOnly)
|
|
{
|
|
GdiComment(MetafileHdc, sizeData, data);
|
|
return Ok;
|
|
}
|
|
}
|
|
WARNING(("Failed to write Comment record"));
|
|
return GenericError;
|
|
}
|
|
|
|
GpStatus
|
|
MetafileRecorder::RecordHeader(
|
|
INT logicalDpiX,
|
|
INT logicalDpiY,
|
|
INT emfPlusFlags
|
|
)
|
|
{
|
|
// Don't need to check for EmfPlusStream or Valid
|
|
|
|
UINT32 dataSize = sizeof(EmfPlusHeaderRecord);
|
|
EmfPlusRecordType type = EmfPlusRecordTypeHeader;
|
|
INT flags = 0;
|
|
|
|
if (Type != EmfTypeEmfPlusOnly)
|
|
{
|
|
flags |= GDIP_EPRFLAGS_EMFPLUSDUAL;
|
|
}
|
|
|
|
EmfPlusHeaderRecord emfPlusHeader(emfPlusFlags, logicalDpiX, logicalDpiY);
|
|
|
|
WriteRecordHeader(dataSize, type, flags);
|
|
WriteBytes(EmfPlusStream, &emfPlusHeader, sizeof(emfPlusHeader));
|
|
|
|
// We have to flush the EMF+ header immediately to guarantee that it
|
|
// is the first record in the EMF after the EMF header. Otherwise,
|
|
// CloneColorAdjusted fails, because immediately after the metafile
|
|
// constructor, it calls Play into the new metafile which writes a
|
|
// SaveDC record into the metafile.
|
|
EmfPlusStream->Flush();
|
|
|
|
if (EmfPlusStream->IsValid())
|
|
{
|
|
return Ok;
|
|
}
|
|
SetValid(FALSE);
|
|
WARNING(("Failed to write Metafile Header record"));
|
|
return Win32Error;
|
|
}
|
|
|
|
VOID
|
|
MetafileRecorder::RecordEndOfFile()
|
|
{
|
|
RecordZeroDataRecord(EmfPlusRecordTypeEndOfFile, 0);
|
|
}
|
|
|
|
extern "C"
|
|
int CALLBACK
|
|
EnumEmfToStream(
|
|
HDC hdc,
|
|
HANDLETABLE FAR * gdiHandleTable,
|
|
CONST ENHMETARECORD * emfRecord,
|
|
int numHandles,
|
|
LPARAM stream
|
|
);
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* IMetafileRecord interface method - EndRecording.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* NONE
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
VOID
|
|
MetafileRecorder::EndRecording()
|
|
{
|
|
GpMetafile::MetafileState state = GpMetafile::InvalidMetafileState;
|
|
|
|
if (IsValid() && (Metafile->State == GpMetafile::RecordingMetafileState))
|
|
{
|
|
INT success = 1; // assume success
|
|
|
|
// If doing down-level only, then EmfPlusStream will be NULL
|
|
if (EmfPlusStream != NULL)
|
|
{
|
|
// Force a flush of the Stream buffer to the EMF+ file
|
|
EmfPlusStream->Flush();
|
|
|
|
// We put a no-op PatBlt into the metafile to guarantee that
|
|
// the header of the metafile has the same size bounds and
|
|
// frame rect that GDI+ has recorded so that the EMF will
|
|
// play back the same way, whether GDI plays it back or we do.
|
|
// Otherwise, this may not be the case. For example, on a
|
|
// bezier curve, the GDI+ bounds would include the control
|
|
// points, whereas the down-level representation may not.
|
|
|
|
// If we haven't written any records to the file, then XMinDevice
|
|
// and other bounds are still initialized at FLT_MAX and can cause
|
|
// an exception. We don't need the empty PatBlt record in that case
|
|
// because we haven't written anything.
|
|
if (BoundsInit != FALSE)
|
|
{
|
|
// Try to match the GDI+ rasterizer
|
|
INT left = RasterizerCeiling(XMinDevice);
|
|
INT top = RasterizerCeiling(YMinDevice);
|
|
INT right = RasterizerCeiling(XMaxDevice); // exclusive
|
|
INT bottom = RasterizerCeiling(YMaxDevice); // exclusive
|
|
|
|
// to get the inclusive right and bottom, we'd now
|
|
// have to subtract 1 from each of them
|
|
if ((right > left) && (bottom > top))
|
|
{
|
|
Metafile->MetaGraphics->NoOpPatBlt(left, top, right - left, bottom - top);
|
|
}
|
|
}
|
|
|
|
// must be the last record in the file, except the EMF EOF record
|
|
RecordEndOfFile();
|
|
EmfPlusStream->Flush();
|
|
}
|
|
|
|
HENHMETAFILE hEmf = CloseEnhMetaFile(MetafileHdc);
|
|
|
|
if (hEmf == NULL)
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
// Get the EMF header
|
|
ENHMETAHEADER3 emfHeader;
|
|
if ((GetEnhMetaFileHeader(hEmf, sizeof(emfHeader),
|
|
(ENHMETAHEADER*)(&emfHeader)) <= 0) ||
|
|
!EmfHeaderIsValid(emfHeader))
|
|
{
|
|
DeleteEnhMetaFile(hEmf);
|
|
goto Done;
|
|
}
|
|
|
|
#if DBG
|
|
if ((emfHeader.rclBounds.right == -1) &&
|
|
(emfHeader.rclBounds.bottom == -1) &&
|
|
(emfHeader.rclBounds.left == 0) &&
|
|
(emfHeader.rclBounds.top == 0))
|
|
{
|
|
WARNING1("Empty metafile -- no drawing records");
|
|
}
|
|
#endif
|
|
|
|
MetafileHeader * header = &Metafile->Header;
|
|
INT32 emfPlusFlags = header->EmfPlusFlags;
|
|
|
|
// Save the header and various other info in the Metafile
|
|
Metafile->Hemf = hEmf;
|
|
Metafile->MaxStackSize = MaxStackSize;
|
|
header->EmfPlusFlags = emfPlusFlags;
|
|
header->EmfHeader = emfHeader;
|
|
header->Size = emfHeader.nBytes;
|
|
|
|
// Set the bounds in the Metafile header
|
|
{
|
|
REAL multiplierX = header->DpiX / 2540.0f;
|
|
REAL multiplierY = header->DpiY / 2540.0f;
|
|
|
|
// The frameRect is inclusive-inclusive, but the bounds in
|
|
// the header is inclusive-exclusive.
|
|
REAL x = (multiplierX * (REAL)(emfHeader.rclFrame.left));
|
|
REAL y = (multiplierY * (REAL)(emfHeader.rclFrame.top));
|
|
REAL w = (multiplierX * (REAL)(emfHeader.rclFrame.right -
|
|
emfHeader.rclFrame.left)) + 1.0f;
|
|
REAL h = (multiplierY * (REAL)(emfHeader.rclFrame.bottom -
|
|
emfHeader.rclFrame.top)) + 1.0f;
|
|
header->X = GpRound(x);
|
|
header->Y = GpRound(y);
|
|
header->Width = GpRound(w);
|
|
header->Height = GpRound(h);
|
|
}
|
|
|
|
// The metafile is either supposed to be in memory, in a file,
|
|
// or in a stream.
|
|
|
|
// If it goes in a file, we're done unless we need to rewrite
|
|
// any of the header information.
|
|
if (Metafile->Filename != NULL)
|
|
{
|
|
state = GpMetafile::DoneRecordingMetafileState;
|
|
}
|
|
else
|
|
{
|
|
// If it goes in memory, we're done.
|
|
|
|
// If it goes in a stream, then we have to write
|
|
// the bits to the stream.
|
|
|
|
if (Metafile->Stream != NULL)
|
|
{
|
|
// Write the emf data buffer to the stream,
|
|
// and leave the stream position at the end of the metafile.
|
|
if (!::EnumEnhMetaFile(NULL, hEmf, EnumEmfToStream,
|
|
Metafile->Stream, NULL))
|
|
{
|
|
WARNING(("Problem retrieving EMF Data"));
|
|
DeleteEnhMetaFile(hEmf);
|
|
Metafile->Hemf = NULL;
|
|
goto Done;
|
|
}
|
|
|
|
// Don't need the Stream any longer
|
|
Metafile->Stream->Release();
|
|
Metafile->Stream = NULL;
|
|
}
|
|
state = GpMetafile::DoneRecordingMetafileState;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DeleteEnhMetaFile(CloseEnhMetaFile(MetafileHdc));
|
|
WARNING(("Metafile in wrong state in EndRecording"));
|
|
}
|
|
|
|
Done:
|
|
Metafile->MetaGraphics->Metafile = NULL; // Graphics can't point to us anymore
|
|
Metafile->MetaGraphics->SetValid(FALSE); // Don't allow anymore operations on
|
|
// the graphics
|
|
Metafile->MetaGraphics = NULL; // graphics is not valid any more
|
|
Metafile->State = state;
|
|
delete this;
|
|
}
|
|
|
|
#if 0
|
|
inline INT
|
|
WriteActualSize(
|
|
IStream * stream,
|
|
LONGLONG & startOfRecord,
|
|
ULONG actualSize
|
|
)
|
|
{
|
|
ASSERT (actualSize > 0);
|
|
|
|
// get to size field
|
|
INT success = SeekFromStart(stream, startOfRecord + sizeof(INT32));
|
|
|
|
if (success)
|
|
{
|
|
success &= WriteInt32(stream, actualSize);
|
|
}
|
|
|
|
// get back to end of record
|
|
success &= SeekFromStart(stream, startOfRecord + actualSize);
|
|
|
|
return success;
|
|
}
|
|
#endif
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Write an object (pen, brush, image, region, path, font) to metafile by
|
|
* writing its header, calling its serialize method, and then re-writing
|
|
* the size.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] type - the record type
|
|
* [IN] flags - any flags for the record header
|
|
* [IN] object - pointer to the object to be recorded
|
|
* [IN] metaObjectId - ID to store in file that identifies object
|
|
* [IN] extraData - any extra data to store with object
|
|
* [IN] extraDataSize - size in BYTES of extraData
|
|
*
|
|
* Return Value:
|
|
*
|
|
* INT - 1 if we succeeded, else 0 if we failed
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
VOID
|
|
MetafileRecorder::WriteObject(
|
|
ObjectType type,
|
|
const GpObject * object,
|
|
UINT32 metaObjectId
|
|
)
|
|
{
|
|
ULONG objectDataSize = object->GetDataSize();
|
|
INT flags = ((INT)type << 8);
|
|
|
|
ASSERT((objectDataSize & 0x03) == 0);
|
|
ASSERT((flags & (~GDIP_EPRFLAGS_OBJECTTYPE)) == 0);
|
|
ASSERT((metaObjectId & (~GDIP_EPRFLAGS_METAOBJECTID)) == 0);
|
|
ASSERT(objectDataSize != 0); // cannot have an empty object
|
|
|
|
flags |= metaObjectId;
|
|
|
|
WriteRecordHeader(objectDataSize, EmfPlusRecordTypeObject, flags, NULL);
|
|
|
|
if (object->GetData(EmfPlusStream) != Ok)
|
|
{
|
|
WARNING(("GetData failed"));
|
|
}
|
|
EmfPlusStream->EndObjectRecord();
|
|
}
|
|
|
|
VOID
|
|
MetafileRecorder::RecordObject(
|
|
const GpObject * object,
|
|
UINT32* metaObjectId
|
|
)
|
|
{
|
|
if (object)
|
|
{
|
|
ObjectType type = object->GetObjectType();
|
|
|
|
if (ObjectList.IsInList(object, type, metaObjectId))
|
|
{
|
|
ObjectList.UpdateMRU(*metaObjectId);
|
|
}
|
|
else
|
|
{
|
|
ObjectList.InsertAt(object, metaObjectId);
|
|
WriteObject(type, object, *metaObjectId);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*metaObjectId = GDIP_OBJECTID_NONE;
|
|
}
|
|
}
|
|
|
|
// This is for backward compatiblity. If we are using a new object
|
|
// (such as a new kind of brush), then we can record a backup object
|
|
// for down-level apps to use when they see a new object that they
|
|
// don't know how to deal with.
|
|
GpStatus
|
|
MetafileRecorder::RecordBackupObject(
|
|
const GpObject * object
|
|
)
|
|
{
|
|
WriteObject(object->GetObjectType(), object, GDIP_BACKUP_OBJECTID) ;
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Write the initial portion of an EMF+ record. Every EMF+ record contains
|
|
* a size, a type, and some flags. Many also contain a rect that specifies
|
|
* the bounds of a drawing operation in REAL device units.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] size - the size of the record (excluding the header)
|
|
* [IN] type - the EMF+ record type
|
|
* [IN] flags - any flags that are defined for this record
|
|
* [IN] deviceBounds - bounds of drawing operation, or NULL
|
|
*
|
|
* Return Value:
|
|
*
|
|
* INT - 1 if we succeeded, else 0 if we failed
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
VOID
|
|
MetafileRecorder::WriteRecordHeader(
|
|
UINT32 dataSize,
|
|
EmfPlusRecordType type,
|
|
INT flags, // 16 bits of flags
|
|
const GpRectF * deviceBounds
|
|
)
|
|
{
|
|
ASSERT((dataSize & 0x03) == 0);
|
|
|
|
EmfPlusStream->WriteRecordHeader(dataSize, type, flags);
|
|
|
|
NumRecords++;
|
|
|
|
if (deviceBounds != NULL)
|
|
{
|
|
// If the bounds aren't initalized then make sure we have 4 valid
|
|
// coordinates
|
|
ASSERT(BoundsInit ||
|
|
((deviceBounds->X < XMinDevice) &&
|
|
(deviceBounds->GetRight() > XMaxDevice) &&
|
|
(deviceBounds->Y < YMinDevice) &&
|
|
(deviceBounds->GetBottom() > YMaxDevice)));
|
|
BoundsInit = TRUE;
|
|
// Update the device bounds
|
|
if (deviceBounds->X < XMinDevice)
|
|
{
|
|
XMinDevice = deviceBounds->X;
|
|
}
|
|
if (deviceBounds->GetRight() > XMaxDevice)
|
|
{
|
|
XMaxDevice = deviceBounds->GetRight(); // exclusive
|
|
}
|
|
if (deviceBounds->Y < YMinDevice)
|
|
{
|
|
YMinDevice = deviceBounds->Y;
|
|
}
|
|
if (deviceBounds->GetBottom() > YMaxDevice)
|
|
{
|
|
YMaxDevice = deviceBounds->GetBottom(); // exclusive
|
|
}
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* If the brush is a 32-bit solid color, then return the solid color as
|
|
* the brush value and set the flags to indicate it's a solid color.
|
|
* Otherwise, record the brush and return the metafile brush id as the
|
|
* brush value.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] brush - the brush that needs to be recorded
|
|
* [OUT] brushValue - the 32-bit color or metafile brush ID
|
|
* [OUT] flags - set if we're using a solid color
|
|
*
|
|
* Return Value:
|
|
*
|
|
* INT - 1 if we succeeded, else 0 if we failed
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
VOID
|
|
MetafileRecorder::GetBrushValueForRecording(
|
|
const GpBrush *brush,
|
|
UINT32 &brushValue,
|
|
INT &flags
|
|
)
|
|
{
|
|
if (brush->GetBrushType() == BrushTypeSolidColor)
|
|
{
|
|
const GpSolidFill * solidBrush = static_cast<const GpSolidFill *>(brush);
|
|
brushValue = solidBrush->GetColor().GetValue();
|
|
flags |= GDIP_EPRFLAGS_SOLIDCOLOR;
|
|
}
|
|
else
|
|
{
|
|
RecordObject(brush, &brushValue);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* GpMetafile constructor for write/read access to a metafile. (Write must
|
|
* precede the read.)
|
|
*
|
|
* This version records an EMF+ to memory. The type specifies whether
|
|
* to record dual GDI records or not.
|
|
*
|
|
* If the frameRect is NULL, it will be calculated by accumulating the
|
|
* device bounds of the metafile. Otherwise, the supplied frameRect and
|
|
* corresponding frameUnit will be used to record the frameRect in the
|
|
* metafile header. The frameRect is inclusive-inclusive, which means
|
|
* that the width value is actually 1 less than the actual width.
|
|
* For example, a width of 0 is accepted and really means a width of 1.
|
|
*
|
|
* If the optional description is supplied, it will become part of the
|
|
* EMF header.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] fileName - where to write the metafile
|
|
* [IN] referenceHdc - an HDC to use as a reference for creating metafile
|
|
* [IN] type - whether to record EMF+-only or EMF+-dual
|
|
* [IN] frameRect - optional frame rect for recording in header
|
|
* [IN] frameUnit - the units of the frameRect
|
|
* [IN] description - optional metafile description
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpMetafile::GpMetafile(
|
|
HDC referenceHdc,
|
|
EmfType type,
|
|
const GpRectF * frameRect, // can be NULL
|
|
MetafileFrameUnit frameUnit, // if NULL frameRect, doesn't matter
|
|
const WCHAR * description // can be NULL
|
|
) : GpImage(ImageTypeMetafile)
|
|
{
|
|
ASSERT(referenceHdc != NULL);
|
|
|
|
InitDefaults();
|
|
|
|
if ((referenceHdc != NULL) &&
|
|
InitForRecording(
|
|
referenceHdc,
|
|
type,
|
|
frameRect, // can be NULL
|
|
frameUnit, // if NULL frameRect, doesn't matter
|
|
description // can be NULL
|
|
))
|
|
{
|
|
State = RecordingMetafileState;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* GpMetafile constructor for write/read access to a metafile. (Write must
|
|
* precede the read.)
|
|
*
|
|
* This version records an EMF+ to a file. The type specifies whether
|
|
* to record dual GDI records or not.
|
|
*
|
|
* If the frameRect is NULL, it will be calculated by accumulating the
|
|
* device bounds of the metafile. Otherwise, the supplied frameRect and
|
|
* corresponding frameUnit will be used to record the frameRect in the
|
|
* metafile header. The frameRect is inclusive-inclusive, which means
|
|
* that the width value is actually 1 less than the actual width.
|
|
* For example, a width of 0 is accepted and really means a width of 1.
|
|
*
|
|
* If the optional description is supplied, it will become part of the
|
|
* EMF header.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] fileName - where to write the metafile
|
|
* [IN] referenceHdc - an HDC to use as a reference for creating metafile
|
|
* [IN] type - whether to record EMF+-only or EMF+-dual
|
|
* [IN] frameRect - optional frame rect for recording in header
|
|
* [IN] frameUnit - the units of the frameRect
|
|
* [IN] description - optional metafile description
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpMetafile::GpMetafile(
|
|
const WCHAR* fileName,
|
|
HDC referenceHdc,
|
|
EmfType type,
|
|
const GpRectF * frameRect, // can be NULL
|
|
MetafileFrameUnit frameUnit, // if NULL frameRect, doesn't matter
|
|
const WCHAR * description // can be NULL
|
|
) : GpImage(ImageTypeMetafile)
|
|
{
|
|
ASSERT((fileName != NULL) && (referenceHdc != NULL));
|
|
|
|
InitDefaults();
|
|
|
|
if ((fileName != NULL) && (referenceHdc != NULL) &&
|
|
((Filename = UnicodeStringDuplicate(fileName)) != NULL) &&
|
|
InitForRecording(
|
|
referenceHdc,
|
|
type,
|
|
frameRect, // can be NULL
|
|
frameUnit, // if NULL frameRect, doesn't matter
|
|
description // can be NULL
|
|
))
|
|
{
|
|
State = RecordingMetafileState;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* GpMetafile constructor for write/read access to a metafile. (Write must
|
|
* precede the read.)
|
|
*
|
|
* This version records an EMF+ to a file. The type specifies whether
|
|
* to record dual GDI records or not.
|
|
*
|
|
* The metafile is first recorded to a temporary file, then it is copied
|
|
* from the file into the stream.
|
|
*
|
|
* If the frameRect is NULL, it will be calculated by accumulating the
|
|
* device bounds of the metafile. Otherwise, the supplied frameRect and
|
|
* corresponding frameUnit will be used to record the frameRect in the
|
|
* metafile header. The frameRect is inclusive-inclusive, which means
|
|
* that the width value is actually 1 less than the actual width.
|
|
* For example, a width of 0 is accepted and really means a width of 1.
|
|
*
|
|
* If the optional description is supplied, it will become part of the
|
|
* EMF header.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] stream - where to copy the metafile, after it's recorded
|
|
* [IN] referenceHdc - an HDC to use as a reference for creating metafile
|
|
* [IN] type - whether to record EMF+-only or EMF+-dual
|
|
* [IN] frameRect - optional frame rect for recording in header
|
|
* [IN] frameUnit - the units of the frameRect
|
|
* [IN] description - optional metafile description
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
GpMetafile::GpMetafile(
|
|
IStream * stream,
|
|
HDC referenceHdc,
|
|
EmfType type,
|
|
const GpRectF * frameRect, // can be NULL
|
|
MetafileFrameUnit frameUnit, // if NULL frameRect, doesn't matter
|
|
const WCHAR * description // can be NULL
|
|
) : GpImage(ImageTypeMetafile)
|
|
{
|
|
ASSERT((stream != NULL) && (referenceHdc != NULL));
|
|
|
|
InitDefaults();
|
|
|
|
if ((stream != NULL) && (referenceHdc != NULL))
|
|
{
|
|
if (InitForRecording(
|
|
referenceHdc,
|
|
type,
|
|
frameRect, // can be NULL
|
|
frameUnit, // if NULL frameRect, doesn't matter
|
|
description // can be NULL
|
|
))
|
|
{
|
|
stream->AddRef();
|
|
Stream = stream;
|
|
State = RecordingMetafileState;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline HDC CreateEmf(
|
|
HDC referenceHdc,
|
|
const WCHAR * fileName,
|
|
RECT * frameRect
|
|
)
|
|
{
|
|
HDC metafileHdc = NULL;
|
|
|
|
if (Globals::IsNt)
|
|
{
|
|
metafileHdc = CreateEnhMetaFileW(referenceHdc, fileName, frameRect, NULL);
|
|
}
|
|
else
|
|
{
|
|
AnsiStrFromUnicode fileBuffer(fileName);
|
|
|
|
if (fileBuffer.IsValid())
|
|
{
|
|
metafileHdc = CreateEnhMetaFileA(referenceHdc, fileBuffer, frameRect, NULL);
|
|
}
|
|
}
|
|
return metafileHdc;
|
|
}
|
|
|
|
static BOOL
|
|
GetFrameRectInMM100Units(
|
|
HDC hdc,
|
|
const GpRectF * frameRect,
|
|
MetafileFrameUnit frameUnit,
|
|
RECT & rclFrame
|
|
)
|
|
{
|
|
SIZEL szlDevice; // Size of device in pels
|
|
SIZEL szlMillimeters; // Size of device in millimeters
|
|
REAL dpiX;
|
|
REAL dpiY;
|
|
|
|
// NOTE: We have to use the szlDevice and szlMillimeters to get
|
|
// the dpi (instead of getting it directly from LOGPIXELSX/Y)
|
|
// so that the frame rect that is calculated for the metafile by GDI
|
|
// matches the one that GDI+ would have calculated. Because it's
|
|
// these 2 metrics that the GDI metafile code uses to get the frame
|
|
// rect from the bounds, not the logical DPI.
|
|
|
|
szlDevice.cx = ::GetDeviceCaps(hdc, HORZRES);
|
|
szlDevice.cy = ::GetDeviceCaps(hdc, VERTRES);
|
|
szlMillimeters.cx = ::GetDeviceCaps(hdc, HORZSIZE);
|
|
szlMillimeters.cy = ::GetDeviceCaps(hdc, VERTSIZE);
|
|
|
|
if ((szlDevice.cx <= 0) || (szlDevice.cy <= 0) ||
|
|
(szlMillimeters.cx <= 0) || (szlMillimeters.cy <= 0))
|
|
{
|
|
WARNING(("GetDeviceCaps failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
// Now get the real DPI, adjusted for the round-off error.
|
|
dpiX = ((REAL)(szlDevice.cx) / (REAL)(szlMillimeters.cx)) * 25.4f;
|
|
dpiY = ((REAL)(szlDevice.cy) / (REAL)(szlMillimeters.cy)) * 25.4f;
|
|
|
|
GpRectF frameRectMM100;
|
|
|
|
FrameToMM100(frameRect, (GpPageUnit)frameUnit, frameRectMM100,
|
|
dpiX, dpiY);
|
|
|
|
rclFrame.left = GpRound(frameRectMM100.X);
|
|
rclFrame.top = GpRound(frameRectMM100.Y);
|
|
rclFrame.right = GpRound(frameRectMM100.GetRight());
|
|
rclFrame.bottom = GpRound(frameRectMM100.GetBottom());
|
|
|
|
// Make sure the .01MM frameRect is valid
|
|
// It's okay for left == right, because the frameRect
|
|
// is inclusive-inclusive.
|
|
if ((rclFrame.left > rclFrame.right) ||
|
|
(rclFrame.top > rclFrame.bottom))
|
|
{
|
|
WARNING(("Invalid GDI frameRect"));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Convert a frameRect in any units, to a frame rect that is in .01 MM units.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* [IN] frameRect - the source frameRect
|
|
* [IN] frameUnit - the units of the source frameRect
|
|
* [OUT] frameRectMM100 - the frameRect in inch units
|
|
* [IN] dpiX - the horizontal DPI
|
|
* [IN] dpiY - the vertical DPI
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/15/1999 DCurtis
|
|
*
|
|
\**************************************************************************/
|
|
static VOID
|
|
FrameToMM100(
|
|
const GpRectF * frameRect,
|
|
GpPageUnit frameUnit,
|
|
GpRectF & frameRectMM100,
|
|
REAL dpiX, // only used for pixel case
|
|
REAL dpiY
|
|
)
|
|
{
|
|
REAL pixelsToMM100X = (2540.0f / dpiX);
|
|
REAL pixelsToMM100Y = (2540.0f / dpiY);
|
|
|
|
// The GDI frameRect has right and bottom values that are
|
|
// inclusive, whereas the GDI+ frameRect has GetRight() and
|
|
// GetBottom() values that are exclusive (because GDI+ rects
|
|
// are specified with width/height, not right/bottom. To convert
|
|
// from the GDI+ value to the GDI value, we have to subtract 1 pixel.
|
|
// This means that we first convert the units to pixel units, then
|
|
// subtract one, then convert to MM100 units.
|
|
switch (frameUnit)
|
|
{
|
|
default:
|
|
ASSERT(0);
|
|
// FALLTHRU
|
|
|
|
case UnitPixel: // Each unit represents one device pixel.
|
|
frameRectMM100.X = frameRect->X * pixelsToMM100X;
|
|
frameRectMM100.Y = frameRect->Y * pixelsToMM100Y;
|
|
frameRectMM100.Width = frameRect->Width;
|
|
frameRectMM100.Height = frameRect->Height;
|
|
break;
|
|
|
|
case UnitPoint: // Each unit represents 1/72 inch.
|
|
frameRectMM100.X = frameRect->X * (2540.0f / 72.0f);
|
|
frameRectMM100.Y = frameRect->Y * (2540.0f / 72.0f);
|
|
frameRectMM100.Width = frameRect->Width * (dpiX / 72.0f);
|
|
frameRectMM100.Height = frameRect->Height * (dpiY / 72.0f);
|
|
break;
|
|
|
|
case UnitInch: // Each unit represents 1 inch.
|
|
frameRectMM100.X = frameRect->X * 2540.0f;
|
|
frameRectMM100.Y = frameRect->Y * 2540.0f;
|
|
frameRectMM100.Width = frameRect->Width * dpiX;
|
|
frameRectMM100.Height = frameRect->Height * dpiY;
|
|
break;
|
|
|
|
case UnitDocument: // Each unit represents 1/300 inch.
|
|
frameRectMM100.X = frameRect->X * (2540.0f / 300.0f);
|
|
frameRectMM100.Y = frameRect->Y * (2540.0f / 300.0f);
|
|
frameRectMM100.Width = frameRect->Width * (dpiX / 300.0f);
|
|
frameRectMM100.Height = frameRect->Height * (dpiY / 300.0f);
|
|
break;
|
|
|
|
case UnitMillimeter: // Each unit represents 1 millimeter.
|
|
// One Millimeter is 0.03937 inches
|
|
// One Inch is 25.4 millimeters
|
|
frameRectMM100.X = frameRect->X * (100.0f);
|
|
frameRectMM100.Y = frameRect->Y * (100.0f);
|
|
frameRectMM100.Width = frameRect->Width * (dpiX / 25.4f);
|
|
frameRectMM100.Height = frameRect->Height * (dpiY / 25.4f);
|
|
break;
|
|
}
|
|
frameRectMM100.Width = (frameRectMM100.Width - 1.0f) * pixelsToMM100X;
|
|
frameRectMM100.Height = (frameRectMM100.Height - 1.0f) * pixelsToMM100Y;
|
|
}
|
|
|
|
BOOL
|
|
GpMetafile::InitForRecording(
|
|
HDC referenceHdc,
|
|
EmfType type,
|
|
const GpRectF * frameRect, // can be NULL
|
|
MetafileFrameUnit frameUnit, // if NULL frameRect, doesn't matter
|
|
const WCHAR * description // can be NULL
|
|
)
|
|
{
|
|
RECT * frameRectParam = NULL;
|
|
RECT rclFrame;
|
|
|
|
if (frameRect != NULL)
|
|
{
|
|
// Validate the frameRect
|
|
// 0 is allowed, since the frameRect is inclusive-inclusive, which
|
|
// means that a width of 0 is actually a width of 1
|
|
if ((frameRect->Width < 0.0f) || (frameRect->Height < 0.0f))
|
|
{
|
|
WARNING(("Invalid frameRect"));
|
|
return FALSE;
|
|
}
|
|
|
|
if (frameUnit == MetafileFrameUnitGdi)
|
|
{
|
|
// Typically, the GDI+ frameRect is inclusive/exclusive
|
|
// as far as the GetLeft()/GetRight() values go, but the
|
|
// MetafileFrameUnitGdi unit is a special type of unit
|
|
// that specifies compatibility with GDI which is
|
|
// inclusive/inclusive, so we don't do any adjustment
|
|
// on those values at all -- we just assume they are ready
|
|
// to pass directly to GDI.
|
|
rclFrame.left = GpRound(frameRect->X);
|
|
rclFrame.top = GpRound(frameRect->Y);
|
|
rclFrame.right = GpRound(frameRect->GetRight());
|
|
rclFrame.bottom = GpRound(frameRect->GetBottom());
|
|
|
|
// Make sure the .01MM frameRect is valid
|
|
// It's okay for left == right, because the GDI frameRect
|
|
// is inclusive-inclusive.
|
|
if ((rclFrame.left > rclFrame.right) ||
|
|
(rclFrame.top > rclFrame.bottom))
|
|
{
|
|
WARNING(("Invalid GDI frameRect"));
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!GetFrameRectInMM100Units(referenceHdc, frameRect, frameUnit, rclFrame))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
frameRectParam = &rclFrame;
|
|
}
|
|
|
|
HDC metafileHdc;
|
|
|
|
// Now create the metafile HDC
|
|
// Note that FileName might be NULL
|
|
metafileHdc = CreateEmf(referenceHdc, Filename, frameRectParam);
|
|
if (metafileHdc == NULL)
|
|
{
|
|
return FALSE; // failed
|
|
}
|
|
|
|
// Now get the dpi based on the metafileHdc (which could be different
|
|
// than the referenceHdc).
|
|
|
|
SIZEL szlDevice; // Size of metafile device in pels
|
|
SIZEL szlMillimeters; // Size of metafile device in millimeters
|
|
GpRectF metafileBounds;
|
|
|
|
// NOTE: We have to use the szlDevice and szlMillimeters to get
|
|
// the dpi (instead of getting it directly from LOGPIXELSX/Y)
|
|
// so that the frame rect that is calculated for the metafile by GDI
|
|
// matches the one that GDI+ would have calculated. Because it's
|
|
// these 2 metrics that the GDI metafile code uses to get the frame
|
|
// rect from the bounds, not the logical DPI.
|
|
|
|
szlDevice.cx = ::GetDeviceCaps(metafileHdc, HORZRES);
|
|
szlDevice.cy = ::GetDeviceCaps(metafileHdc, VERTRES);
|
|
szlMillimeters.cx = ::GetDeviceCaps(metafileHdc, HORZSIZE);
|
|
szlMillimeters.cy = ::GetDeviceCaps(metafileHdc, VERTSIZE);
|
|
|
|
if ((szlDevice.cx <= 0) || (szlDevice.cy <= 0) ||
|
|
(szlMillimeters.cx <= 0) || (szlMillimeters.cy <= 0))
|
|
{
|
|
WARNING(("GetDeviceCaps failed"));
|
|
goto ErrorExit;
|
|
}
|
|
|
|
REAL dpiX;
|
|
REAL dpiY;
|
|
REAL dpmmX = (REAL)(szlDevice.cx) / (REAL)(szlMillimeters.cx);
|
|
REAL dpmmY = (REAL)(szlDevice.cy) / (REAL)(szlMillimeters.cy);
|
|
|
|
// Now get the real DPI, adjusted for the round-off error.
|
|
dpiX = dpmmX * 25.4f;
|
|
dpiY = dpmmY * 25.4f;
|
|
|
|
// Set the DPI in the metafile
|
|
this->Header.DpiX = dpiX;
|
|
this->Header.DpiY = dpiY;
|
|
|
|
// NOTE: On Win9x there are some hi-res printer drivers that use a
|
|
// different resolution for the metafileHdc than they do for the
|
|
// referenceHdc (Probably to avoid overflow.) The problem with that
|
|
// is, that the differing resolutions make it impossible for us to
|
|
// know which frameRect to use, because we don't know for certain
|
|
// what DPI the application is going to assume to do its drawing --
|
|
// whether the metafile resolution or the printer resolution. In any
|
|
// case, it's a safe bet that the original frameRect is wrong.
|
|
|
|
if (!Globals::IsNt && (frameRectParam != NULL) &&
|
|
(::GetDeviceCaps(metafileHdc, LOGPIXELSX) != ::GetDeviceCaps(referenceHdc, LOGPIXELSX)))
|
|
{
|
|
frameRectParam = NULL; // give up on the frameRect
|
|
|
|
// Now recreate the metafile HDC
|
|
::DeleteEnhMetaFile(::CloseEnhMetaFile(metafileHdc));
|
|
metafileHdc = CreateEmf(referenceHdc, Filename, frameRectParam);
|
|
if (metafileHdc == NULL)
|
|
{
|
|
return FALSE; // failed
|
|
}
|
|
}
|
|
|
|
// The metafileBounds are used as the bounds for FillRegion
|
|
// calls when the region has infinite bounds, to keep from
|
|
// exploding the bounds of the metafile.
|
|
if (frameRectParam != NULL)
|
|
{
|
|
|
|
dpmmX *= 0.01f;
|
|
dpmmY *= 0.01f;
|
|
|
|
metafileBounds.X = rclFrame.left * dpmmX;
|
|
metafileBounds.Y = rclFrame.top * dpmmY;
|
|
metafileBounds.Width = (rclFrame.right - rclFrame.left) * dpmmX;
|
|
metafileBounds.Height = (rclFrame.bottom - rclFrame.top) * dpmmY;
|
|
}
|
|
else
|
|
{
|
|
metafileBounds.X = 0.0f;
|
|
metafileBounds.Y = 0.0f;
|
|
metafileBounds.Width = (REAL)szlDevice.cx - 1; // metafile bounds are inclusive
|
|
metafileBounds.Height = (REAL)szlDevice.cy - 1;
|
|
}
|
|
|
|
// Now create the recorder object
|
|
MetafileRecorder * recorder = new MetafileRecorder(
|
|
this,
|
|
type,
|
|
metafileHdc,
|
|
(frameRectParam != NULL),
|
|
szlMillimeters,
|
|
metafileBounds);
|
|
if (CheckValid(recorder))
|
|
{
|
|
MetaGraphics = GpGraphics::GetForMetafile(recorder, type, metafileHdc);
|
|
if (MetaGraphics != NULL)
|
|
{
|
|
if (MetaGraphics->IsValid())
|
|
{
|
|
return TRUE;
|
|
}
|
|
recorder->SetValid(FALSE);// so we don't record stuff in EndRecording
|
|
delete MetaGraphics; // calls EndRecording which deletes recorder
|
|
MetaGraphics = NULL;
|
|
}
|
|
else
|
|
{
|
|
delete recorder;
|
|
}
|
|
}
|
|
ErrorExit:
|
|
DeleteEnhMetaFile(CloseEnhMetaFile(metafileHdc));
|
|
return FALSE;
|
|
}
|
|
|
|
// Returns NULL if the metafile was opened for reading or if already got
|
|
// the context for writing.
|
|
GpGraphics *
|
|
GpMetafile::GetGraphicsContext()
|
|
{
|
|
if (!RequestedMetaGraphics)
|
|
{
|
|
RequestedMetaGraphics = TRUE;
|
|
return MetaGraphics;
|
|
}
|
|
WARNING(("Requesting MetaGraphics more than once"));
|
|
return NULL;
|
|
}
|
|
|
|
GpStatus
|
|
GpMetafile::SetDownLevelRasterizationLimit(
|
|
UINT metafileRasterizationLimitDpi
|
|
)
|
|
{
|
|
ASSERT(IsValid());
|
|
// 0 means restore it to the default value; otherwise, the minumum is 10 dpi
|
|
if ((metafileRasterizationLimitDpi == 0) || (metafileRasterizationLimitDpi >= 10))
|
|
{
|
|
if ((State == GpMetafile::RecordingMetafileState) &&
|
|
(MetaGraphics != NULL))
|
|
{
|
|
MetaGraphics->Context->SetMetafileDownLevelRasterizationLimit(metafileRasterizationLimitDpi);
|
|
return Ok;
|
|
}
|
|
WARNING1("Metafile in Wrong State for this operation");
|
|
return WrongState;
|
|
}
|
|
WARNING1("rasterizationDpiLimit is non-zero but too small");
|
|
return InvalidParameter;
|
|
}
|
|
|
|
GpStatus
|
|
GpMetafile::GetDownLevelRasterizationLimit(
|
|
UINT * metafileRasterizationLimitDpi
|
|
) const
|
|
{
|
|
ASSERT(metafileRasterizationLimitDpi != NULL);
|
|
ASSERT(IsValid());
|
|
if ((State == GpMetafile::RecordingMetafileState) &&
|
|
(MetaGraphics != NULL))
|
|
{
|
|
*metafileRasterizationLimitDpi = MetaGraphics->Context->GetMetafileDownLevelRasterizationLimit();
|
|
return Ok;
|
|
}
|
|
WARNING1("Metafile in Wrong State for this operation");
|
|
return WrongState;
|
|
}
|