X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e9576ca53db96b462ed4c0b4bdf47d64c40203e4..9d5507f7a2701395e1d5c121bd877bb9066ee6ea:/src/mac/carbon/metafile.cpp diff --git a/src/mac/carbon/metafile.cpp b/src/mac/carbon/metafile.cpp index a92874b336..a82cf5bfd0 100644 --- a/src/mac/carbon/metafile.cpp +++ b/src/mac/carbon/metafile.cpp @@ -1,239 +1,353 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: metafile.cpp +// Name: src/mac/carbon/metafile.cpp // Purpose: wxMetaFile, wxMetaFileDC etc. These classes are optional. -// Author: AUTHOR +// Author: Stefan Csomor // Modified by: // Created: 04/01/98 // RCS-ID: $Id$ -// Copyright: (c) AUTHOR -// Licence: wxWindows licence +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// +// +// Currently, the only purpose for making a metafile +// is to put it on the clipboard. -#ifdef __GNUG__ -#pragma implementation "metafile.h" + +#include "wx/wxprec.h" + +#if wxUSE_METAFILE + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/app.h" #endif -#include "wx/object.h" -#include "wx/string.h" -#include "wx/dc.h" -#include "wx/stubs/metafile.h" +#include "wx/metafile.h" #include "wx/clipbrd.h" +#include "wx/mac/uma.h" +#include "wx/graphics.h" +#include "wx/mac/carbon/metafile.h" -extern bool wxClipboardIsOpen; +#include +#include -#if !USE_SHARED_LIBRARY -IMPLEMENT_DYNAMIC_CLASS(wxMetaFile, wxObject) -IMPLEMENT_ABSTRACT_CLASS(wxMetaFileDC, wxDC) -#endif +IMPLEMENT_DYNAMIC_CLASS(wxMetafile, wxObject) +IMPLEMENT_ABSTRACT_CLASS(wxMetafileDC, wxDC) +IMPLEMENT_ABSTRACT_CLASS(wxMetafileDCImpl, wxGCDCImpl) + +#define M_METAFILEREFDATA( a ) ((wxMetafileRefData*)(a).GetRefData()) + +class wxMetafileRefData: public wxGDIRefData +{ +public: + // creates a metafile from memory, assumes ownership + wxMetafileRefData(CFDataRef data); + // prepares a recording metafile + wxMetafileRefData( int width, int height); + // prepares a metafile to be read from a file (if filename is not empty) + wxMetafileRefData( const wxString& filename); + virtual ~wxMetafileRefData(); + + void Init(); + + int GetWidth() const { return m_width; } + int GetHeight() const { return m_height; } + + CGPDFDocumentRef GetPDFDocument() const { return m_pdfDoc; } + void UpdateDocumentFromData() ; + + const wxCFDataRef& GetData() const { return m_data; } + CGContextRef GetContext() const { return m_context; } + + // ends the recording + void Close(); +private: + wxCFDataRef m_data; + wxCFRef m_pdfDoc; + CGContextRef m_context; + + int m_width ; + int m_height ; +}; + +wxMetafileRefData::wxMetafileRefData(CFDataRef data) : + m_data(data) +{ + Init(); + UpdateDocumentFromData(); +} + +wxMetafileRefData::wxMetafileRefData( const wxString& filename ) +{ + Init(); + + if ( !filename.empty() ) + { + wxCFRef cfMutableString(CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(filename))); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormD); + wxCFRef url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kCFURLPOSIXPathStyle, false)); + m_pdfDoc.reset(CGPDFDocumentCreateWithURL(url)); + } +} + + +wxMetafileRefData::wxMetafileRefData( int width, int height) +{ + Init(); + + m_width = width; + m_height = height; + + CGRect r = CGRectMake( 0 , 0 , width , height ); + + CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0); + m_data.reset(data); + CGDataConsumerRef dataConsumer = wxMacCGDataConsumerCreateWithCFData(data); + m_context = CGPDFContextCreate( dataConsumer, (width != 0 && height != 0) ? &r : NULL , NULL ); + CGDataConsumerRelease( dataConsumer ); + if ( m_context ) + { + CGPDFContextBeginPage(m_context, NULL); + + CGColorSpaceRef genericColorSpace = wxMacGetGenericRGBColorSpace(); + + CGContextSetFillColorSpace( m_context, genericColorSpace ); + CGContextSetStrokeColorSpace( m_context, genericColorSpace ); + + CGContextTranslateCTM( m_context , 0 , height ) ; + CGContextScaleCTM( m_context , 1 , -1 ) ; + } +} + +wxMetafileRefData::~wxMetafileRefData() +{ +} + +void wxMetafileRefData::Init() +{ + m_context = NULL; + m_width = -1; + m_height = -1; +} + +void wxMetafileRefData::Close() +{ + CGPDFContextEndPage(m_context); + + CGContextRelease(m_context); + m_context = NULL; + + UpdateDocumentFromData(); +} + +void wxMetafileRefData::UpdateDocumentFromData() +{ + wxCFRef provider(wxMacCGDataProviderCreateWithCFData(m_data)); + m_pdfDoc.reset(CGPDFDocumentCreateWithProvider(provider)); + if ( m_pdfDoc != NULL ) + { + CGPDFPageRef page = CGPDFDocumentGetPage( m_pdfDoc, 1 ); + CGRect rect = CGPDFPageGetBoxRect ( page, kCGPDFMediaBox); + m_width = wx_static_cast(int, rect.size.width); + m_height = wx_static_cast(int, rect.size.height); + } +} wxMetaFile::wxMetaFile(const wxString& file) { - // TODO + m_refData = new wxMetafileRefData(file); } wxMetaFile::~wxMetaFile() { - // TODO } -bool wxMetaFile::SetClipboard(int width, int height) +bool wxMetaFile::IsOk() const +{ + return (M_METAFILEDATA && (M_METAFILEDATA->GetData() != NULL)); +} + +WXHMETAFILE wxMetaFile::GetHMETAFILE() const +{ + return (WXHMETAFILE) (CFDataRef) M_METAFILEDATA->GetData(); +} + +bool wxMetaFile::SetClipboard(int WXUNUSED(width), int WXUNUSED(height)) { - bool alreadyOpen=wxClipboardOpen(); + bool success = true; + +#if wxUSE_DRAG_AND_DROP + if (m_refData == NULL) + return false; + + bool alreadyOpen = wxTheClipboard->IsOpened(); if (!alreadyOpen) { - wxOpenClipboard(); - if (!wxEmptyClipboard()) return FALSE; + wxTheClipboard->Open(); + wxTheClipboard->Clear(); } - bool success = wxSetClipboardData(wxDF_METAFILE,this, width,height); - if (!alreadyOpen) wxCloseClipboard(); - return (bool) success; + + wxDataObject *data = new wxMetafileDataObject( *this ); + success = wxTheClipboard->SetData( data ); + if (!alreadyOpen) + wxTheClipboard->Close(); +#endif + + return success; } -bool wxMetaFile::Play(wxDC *dc) +void wxMetafile::SetHMETAFILE(WXHMETAFILE mf) { - // TODO - return FALSE; + UnRef(); + + m_refData = new wxMetafileRefData((CFDataRef)mf); +} + +#ifndef __LP64__ +void wxMetafile::SetPICT(void* pictHandle) +{ + UnRef(); + + Handle picHandle = (Handle) pictHandle; + HLock(picHandle); + CFDataRef data = CFDataCreateWithBytesNoCopy( kCFAllocatorDefault, (const UInt8*) *picHandle, GetHandleSize(picHandle), kCFAllocatorNull); + wxCFRef provider(wxMacCGDataProviderCreateWithCFData(data)); + QDPictRef pictRef = QDPictCreateWithProvider(provider); + CGRect rect = QDPictGetBounds(pictRef); + m_refData = new wxMetafileRefData(wx_static_cast(int, rect.size.width), + wx_static_cast(int, rect.size.height)); + QDPictDrawToCGContext( ((wxMetafileRefData*) m_refData)->GetContext(), rect, pictRef ); + CFRelease( data ); + QDPictRelease( pictRef ); + ((wxMetafileRefData*) m_refData)->Close(); } +#endif + +bool wxMetaFile::Play(wxDC *dc) +{ + if (!m_refData) + return false; + + if (!dc->IsOk()) + return false; + + { + wxDCImpl *impl = dc->GetImpl(); + wxGCDCImpl *gc_impl = wxDynamicCast(impl, wxGCDCImpl); + if (gc_impl) + { + CGContextRef cg = (CGContextRef) (gc_impl->GetGraphicsContext()->GetNativeContext()); + CGPDFDocumentRef doc = M_METAFILEDATA->GetPDFDocument(); + CGPDFPageRef page = CGPDFDocumentGetPage( doc, 1 ); + wxMacCGContextStateSaver save(cg); + CGContextDrawPDFPage( cg, page ); + } +// CGContextTranslateCTM( cg, 0, bounds.size.width ); +// CGContextScaleCTM( cg, 1, -1 ); + } -/* - * Metafile device context - * - */ + return true; +} -// Original constructor that does not takes origin and extent. If you use this, -// *DO* give origin/extent arguments to wxMakeMetaFilePlaceable. -wxMetaFileDC::wxMetaFileDC(const wxString& file) +wxSize wxMetaFile::GetSize() const { - // TODO + wxSize dataSize = wxDefaultSize; + + if (Ok()) + { + dataSize.x = M_METAFILEDATA->GetWidth(); + dataSize.y = M_METAFILEDATA->GetHeight(); + } + + return dataSize; } +// Metafile device context + // New constructor that takes origin and extent. If you use this, don't // give origin/extent arguments to wxMakeMetaFilePlaceable. -wxMetaFileDC::wxMetaFileDC(const wxString& file, int xext, int yext, int xorg, int yorg) + +wxMetafileDCImpl::wxMetafileDCImpl( + wxDC *owner, + const wxString& filename, + int width, int height, + const wxString& WXUNUSED(description) ) : + wxGCDCImpl( owner ) { - // TODO + wxASSERT_MSG( width != 0 || height != 0, wxT("no arbitration of metafile size supported") ); + wxASSERT_MSG( filename.empty(), wxT("no file based metafile support yet")); + + m_metaFile = new wxMetaFile( filename ); + wxMetafileRefData* metafiledata = new wxMetafileRefData(width, height); + m_metaFile->UnRef(); + m_metaFile->SetRefData( metafiledata ); + + SetGraphicsContext( wxGraphicsContext::CreateFromNative(metafiledata->GetContext())); + m_ok = (m_graphicContext != NULL) ; + + SetMapMode( wxMM_TEXT ); } -wxMetaFileDC::~wxMetaFileDC() +wxMetafileDCImpl::~wxMetafileDCImpl() { } -void wxMetaFileDC::GetTextExtent(const wxString& string, float *x, float *y, - float *descent, float *externalLeading, wxFont *theFont, bool use16bit) +void wxMetafileDCImpl::DoGetSize(int *width, int *height) const { - // TODO + wxCHECK_RET( m_metaFile, wxT("GetSize() doesn't work without a metafile") ); + + wxSize sz = m_metaFile->GetSize(); + if (width) + (*width) = sz.x; + if (height) + (*height) = sz.y; } -wxMetaFile *wxMetaFileDC::Close() +wxMetaFile *wxMetafileDCImpl::Close() { - // TODO - return NULL; + delete m_graphicContext; + m_graphicContext = NULL; + m_ok = false; + + M_METAFILEREFDATA(*m_metaFile)->Close(); + + return m_metaFile; } -void wxMetaFileDC::SetMapMode(int mode) +#if wxUSE_DATAOBJ +size_t wxMetafileDataObject::GetDataSize() const { - // TODO + CFIndex length = 0; + wxMetafileRefData* refData = M_METAFILEREFDATA(m_metafile); + if ( refData ) + length = refData->GetData().GetLength(); + return length; } -#if 0 - -#ifdef __WIN32__ -struct RECT32 +bool wxMetafileDataObject::GetDataHere(void *buf) const { - short left; - short top; - short right; - short bottom; -}; + bool result = false; -struct mfPLACEABLEHEADER { - DWORD key; - short hmf; - RECT32 bbox; - WORD inch; - DWORD reserved; - WORD checksum; -}; -#else -struct mfPLACEABLEHEADER { - DWORD key; - HANDLE hmf; - RECT bbox; - WORD inch; - DWORD reserved; - WORD checksum; -}; -#endif - -/* - * Pass filename of existing non-placeable metafile, and bounding box. - * Adds a placeable metafile header, sets the mapping mode to anisotropic, - * and sets the window origin and extent to mimic the MM_TEXT mapping mode. - * - */ - -bool wxMakeMetaFilePlaceable(const wxString& filename, float scale) -{ - return wxMakeMetaFilePlaceable(filename, 0, 0, 0, 0, scale, FALSE); -} - -bool wxMakeMetaFilePlaceable(const wxString& filename, int x1, int y1, int x2, int y2, float scale, bool useOriginAndExtent) -{ - // I'm not sure if this is the correct way of suggesting a scale - // to the client application, but it's the only way I can find. - int unitsPerInch = (int)(576/scale); - - mfPLACEABLEHEADER header; - header.key = 0x9AC6CDD7L; - header.hmf = 0; - header.bbox.left = (int)(x1); - header.bbox.top = (int)(y1); - header.bbox.right = (int)(x2); - header.bbox.bottom = (int)(y2); - header.inch = unitsPerInch; - header.reserved = 0; - - // Calculate checksum - WORD *p; - mfPLACEABLEHEADER *pMFHead = &header; - for (p =(WORD *)pMFHead,pMFHead -> checksum = 0; - p < (WORD *)&pMFHead ->checksum; ++p) - pMFHead ->checksum ^= *p; - - FILE *fd = fopen((char *)(const char *)filename, "rb"); - if (!fd) return FALSE; - - char tempFileBuf[256]; - wxGetTempFileName("mf", tempFileBuf); - FILE *fHandle = fopen(tempFileBuf, "wb"); - if (!fHandle) - return FALSE; - fwrite((void *)&header, sizeof(unsigned char), sizeof(mfPLACEABLEHEADER), fHandle); - - // Calculate origin and extent - int originX = x1; - int originY = y1; - int extentX = x2 - x1; - int extentY = (y2 - y1); - - // Read metafile header and write - METAHEADER metaHeader; - fread((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fd); - - if (useOriginAndExtent) - metaHeader.mtSize += 15; - else - metaHeader.mtSize += 5; - - fwrite((void *)&metaHeader, sizeof(unsigned char), sizeof(metaHeader), fHandle); - - // Write SetMapMode, SetWindowOrigin and SetWindowExt records - char modeBuffer[8]; - char originBuffer[10]; - char extentBuffer[10]; - METARECORD *modeRecord = (METARECORD *)&modeBuffer; - - METARECORD *originRecord = (METARECORD *)&originBuffer; - METARECORD *extentRecord = (METARECORD *)&extentBuffer; - - modeRecord->rdSize = 4; - modeRecord->rdFunction = META_SETMAPMODE; - modeRecord->rdParm[0] = MM_ANISOTROPIC; - - originRecord->rdSize = 5; - originRecord->rdFunction = META_SETWINDOWORG; - originRecord->rdParm[0] = originY; - originRecord->rdParm[1] = originX; - - extentRecord->rdSize = 5; - extentRecord->rdFunction = META_SETWINDOWEXT; - extentRecord->rdParm[0] = extentY; - extentRecord->rdParm[1] = extentX; - - fwrite((void *)modeBuffer, sizeof(char), 8, fHandle); - - if (useOriginAndExtent) - { - fwrite((void *)originBuffer, sizeof(char), 10, fHandle); - fwrite((void *)extentBuffer, sizeof(char), 10, fHandle); - } - - int ch = -2; - while (ch != EOF) - { - ch = getc(fd); - if (ch != EOF) + wxMetafileRefData* refData = M_METAFILEREFDATA(m_metafile); + if ( refData ) { - putc(ch, fHandle); + CFIndex length = refData->GetData().GetLength(); + if ( length > 0 ) + { + result = true ; + refData->GetData().GetBytes(CFRangeMake(0,length), (UInt8 *) buf); + } } - } - fclose(fHandle); - fclose(fd); - wxRemoveFile(filename); - wxCopyFile(tempFileBuf, filename); - wxRemoveFile(tempFileBuf); - return TRUE; + return result; } +bool wxMetafileDataObject::SetData(size_t len, const void *buf) +{ + wxMetafileRefData* metafiledata = new wxMetafileRefData(wxCFRefFromGet(wxCFDataRef((UInt8*)buf, len).get())); + m_metafile.UnRef(); + m_metafile.SetRefData( metafiledata ); + return true; +} #endif +#endif