/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: macsurf.cpp,v 1.5.20.3 2004/07/09 01:59:02 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

/****************************************************************************
 * 
 *  $Id: macsurf.cpp,v 1.5.20.3 2004/07/09 01:59:02 hubbe Exp $
 *  
 */

#include "hxcom.h"

#include "hxtypes.h"
#include "hxwintyp.h"
#include "hxmap.h"
#include "hxslist.h"
#include "ihxpckts.h"
#include "hxwin.h"
#include "hxengin.h"
#include "hxsite2.h"
#include "chxxtype.h"
#include "hxvctrl.h"
#include "hxvsurf.h"
#include "hxcodec.h"
#include "surface.h"
#include "vidosurf.h"
#include "sitetext.h"
#include "chxpckts.h"
#include "hxevent.h"
#include "bltpatch.h"
#ifndef _MAC_UNIX
#include "hxmm.h"
#endif
#include "hxprefs.h"

#include "hxevent.h"
#include "hxthread.h"

#include "platform/mac/macsurf.h"
#include "platform/mac/macroot.h"
#include "baseroot.h"
#include "basesite.h"
#include "platform/mac/macsite.h"

#include "platform/mac/hx_moreprocesses.h"

#ifndef _MACINTOSH
#ifndef _MAC_UNIX
#error This is the Macintosh platform specific implementation.
#endif
#endif


#include "hxheap.h"
#ifdef _DEBUG
#undef HX_THIS_FILE		
static const char HX_THIS_FILE[] = __FILE__;
#endif


CHXSimpleList CMacSurface::zm_SurfaceList;

void* CMacSurface::zm_pOverlayBuf = nil;
long CMacSurface::zm_nOverlayRowBytes = 0;
RgnHandle CMacSurface::zm_OverlayMaskRgn = NULL;
BOOL CMacSurface::zm_bSafeToOverlayBlit = FALSE;
CMacSurface* CMacSurface::zm_pOverlaySurface = nil;
BOOL CMacSurface::zm_bOverlayRequiresKeyColor = FALSE;
BOOL CMacSurface::zm_bOverlayRequiresDrawBand = FALSE;

ImageSequence CMacSurface::zm_SequenceID = NULL;
ImageDescriptionHandle CMacSurface::zm_ImageDescriptionHandle = NULL;
long CMacSurface::zm_nOverlayBufferSize = 0;

void* CMacSurface::zm_pHoldOverlayBuf = NULL;
long CMacSurface::zm_nHoldOverlayBufSize = 0;


#pragma options align=mac68k

struct BogusCodecDecompressParams
{
    CodecDecompressParams decompParams;
    long dummy[100];
    // XXXbobclark
    // sheesh. OK, when ImageCodecNewImageBufferMemory() is
    // called, memory can be corrupted. The address of a
    // CodecDecompressParams is passed to the call, and it
    // pokes memory past the end of the 210-byte structure.
    // I've reproduced this in ATI's YUVSDK as well. ATI
    // insists that it can't be their fault and they don't
    // think it's Apple's fault either. Whatever. Memory
    // is still getting corrupted. By including a bunch of
    // dummy space, that corruption happens in a harmless
    // place. Instead of, like it was doing for weeks, in
    // some random variable that would cause strange behavior
    // and/or crashes at ill-defined times.
};
typedef BogusCodecDecompressParams BogusCodecDecompressParams;

ComponentInstanceRecord *gYUV = nil;

BogusCodecDecompressParams bogusDecompParams;
ImageSubCodecDecompressRecord drp;

#pragma options align=reset



/************************************************************************
 *  Method:
 *    CMacSurface constructor
 */
CMacSurface::CMacSurface(IUnknown* pContext, CHXBaseSite* pSite)
 : CBaseSurface(pContext, pSite)
{
    zm_SurfaceList.AddTail(this);
}

/************************************************************************
 *  Method:
 *    CHXMacSite destructor
 */
CMacSurface::~CMacSurface()
{
    
    if (CMacSurface::zm_pOverlaySurface == this)
    {
	CleanUpOverlay();
	CMacSurface::zm_pOverlaySurface = nil;
	
	::DisposePtr((Ptr)zm_pHoldOverlayBuf);
	zm_pHoldOverlayBuf = NULL;
	zm_nHoldOverlayBufSize = 0;
    }
    
    LISTPOSITION pos = zm_SurfaceList.Find(this);
    zm_SurfaceList.RemoveAt(pos);
}

/************************************************************************
 *  Method:
 *    CMacSurface::_ReleaseSurface
 */
void
CMacSurface::_ReleaseSurface(CBaseRootSurface* pSurface)
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::_DrawBlack
 */
void
CMacSurface::_DrawBlack(void* pWindow)
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::__Sleep
 */
void
CMacSurface::__Sleep(int milliseconds)
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::_BltToPrimary
 */
HX_RESULT
CMacSurface::_BltToPrimary(REF(HXxRect) rDestRect, REF(HXxRect) rSrcRect)
{
    return HXR_OK;
}


/************************************************************************
 *  Method:
 *    CMacSurface::_CreateBuffer
 */
void
CMacSurface::_CreateBuffer()
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::_GetCaps
 */
HX_RESULT
CMacSurface::_GetCaps(UINT32* pfSurfaceCaps)
{
    // see if it supports stuff like overlay.
    
    if (pfSurfaceCaps)
    {
	*pfSurfaceCaps = 0;
	if (_OverlayAvailable())
	{
	    *pfSurfaceCaps |= HX_OVERLAY;
	}
    }
    return HXR_OK;
}


/************************************************************************
 *  Method:
 *    CMacSurface::_CreateOverlay
 */
HX_RESULT
CMacSurface::_CreateOverlay(BOOL bOverlay, int cid, int x, int y)
{
    HX_ASSERT(_OverlayAvailable());
    if (CMacSurface::zm_pOverlaySurface == nil)
    {
	CMacSurface::zm_pOverlaySurface = this;
	// we don't want to construct the overlay here, uhhh, because
	// we don't yet know WHERE it's gonna be. We'll construct it
	// the first time we need it.
    }
    else if (CMacSurface::zm_pOverlaySurface == this)
    {
	CleanUpOverlay();
    }
    if (CMacSurface::zm_pOverlaySurface == this)
    {
	m_nBltMode = HX_OVERLAY_BLT;
	m_surfaceSize.cx = x;
	m_surfaceSize.cy = y;
    }
    return HXR_OK;
}

// xxxbobclark weird, it looks like the first time the color convertor is used,
// it slams something weird into the mouse pointer. I'm just doing a quick
// (unnoticeable really) cursor switch to obscure the garbagey stuff.
BOOL gDumbCursorRedrawNeeded = FALSE;

/************************************************************************
 *  Method:
 *    CMacSurface::_LockInternalSurface
 */
HX_RESULT
CMacSurface::_LockInternalSurface(UCHAR** ppSurPtr, LONG32* pnSurfPitch, REF(HXxSize) srcSize)
{
    HX_RESULT retVal = HXR_OK;
    
    GrafPtr savePort = nil;
    
    if (IsMacInCooperativeThread())
    {
	::GetPort(&savePort);
	HXxWindow* pWindow = m_pSite->m_pTopLevelSite->GetWindow();
	HX_ASSERT(pWindow);
	
	if (!pWindow)
	{
	    return HXR_FAIL;
	}
	
	HX_ASSERT(pWindow->window);
	::SetPort( GetWindowPort( (WindowPtr)pWindow->window ) );
    }
    
    if (zm_pOverlayBuf == nil)
    {
	CMacSurface::zm_pOverlaySurface = this;
	m_nSurfaceCID = CID_YUY2;
    }

    if (CMacSurface::zm_pOverlaySurface == this)
    {
	static Point sLastPoint = {-1,-1};
	static HXxSize sLastSize = {0,0};
	static HXxSize sLastSrcSize = {0,0};

	static Point sP = {-1,-1};

	HX_ASSERT(m_pSite);
	
	HXxSize s;
	
	m_pSite->GetSize(s);
	
	sP.h = 0;
	sP.v = 0;
	BOOL bOverlayRebuildingRequired = FALSE;
	
	if (sLastPoint.h != sP.h || sLastPoint.v != sP.v) bOverlayRebuildingRequired = TRUE;
	if (sLastSize.cx != s.cx || sLastSize.cy != s.cy) bOverlayRebuildingRequired = TRUE;
	if (sLastSrcSize.cx != srcSize.cx || sLastSrcSize.cy != srcSize.cy) bOverlayRebuildingRequired = TRUE;
	if (zm_pOverlayBuf == nil) bOverlayRebuildingRequired = TRUE;
	
	// xxxbobclark this catch up workaround is necessary because with some
	// parameters of the overlay while the TLC is resizing, a glitch can
	// happen and blits start happening outside of our window onto the
	// desktop.
	// If (a) the overlay extends beyond the window or (b) a mask region
	// is used when creating the overlay, then when the TLC resizes the
	// following sequence of events takes place:
	// 1. overlay (sequenceID) created.
	// 2. blit happens (DecompressSequenceFrameWhen) successfully
	// 3. All future blits fail with slamming the frame onto the
	//    desktop area.
	//
	// But if we ensure that after the first successful blit we
	// then rebuild the overlay, we never encounter the problem
	// in the sequence of events. I need to revisit this!
	// I created a stand-alone app that tried to repro the problem
	// and I couldn't. I added window sizing code to CarbMini and
	// couldn't repro the problem. I don't know if we're getting
	// called when we're in a bad state in the middle of resizing
	// or what.
	//
	// The whole notion of the image sequence technique is that when
	// you know that your grafport is going to be consistent for awhile
	// you can take advantage of that by using a sequence ID so each
	// blit can rely on the parameters that remain consistent. What this
	// workaround is doing is probably that something in the
	// grafport has changed and we haven't detected it. What I don't
	// know, but I should look into the sequence of events of first
	// overlay rebuild, actual SizeWindow() command, second overlay blit
	// that would slam to the desktop if we didn't kludge.
	//
	// Initially I thought that there were two possible kludges that
	// would avoid the problem. One was to delay the Carbon Timer by
	// a millisecond. The other was to use this "catch up" technique.
	// It turns out that when I delayed the Carbon Timer, I was able
	// to reproduce the problem by actively resizing the simple case,
	// and most of the time using a more complex SMIL repro case.
	// The "catch up" technique used to have a simple boolean for
	// whether the kludge should kick in. Now it has a counter that's
	// higher for more complicated SMIL presentations. I don't know
	// what the magic number is, but using a boolean (i.e. "one")
	// was too low in complex SMIL presentations, and the number of
	// sites seems to work.
	//
	// xxxbobclark 20 Sep 02
	
	static ULONG32 sbCatchUp = 0;
	
	RgnHandle newMaskRgn = nil;
	
	if (bOverlayRebuildingRequired)
	{
	    CHXMacSite* pSite = (CHXMacSite*)zm_pOverlaySurface->m_pSite;

	    HXREGION* pEntireReg = HXCreateRegion();
	    HXUnionRegion(pEntireReg, pSite->m_Region, pEntireReg);

	    // xxxbobclark do this "manual clipping" thing to ensure that opaque
	    // parents are clipped out.
	    CHXMacSite* parentSite = (CHXMacSite*)pSite->GetParentSite();
	    while (parentSite)
	    {
		HXIntersectRegion(pEntireReg, parentSite->m_RegionWithoutChildren, pEntireReg);
		parentSite = (CHXMacSite*)parentSite->GetParentSite();
	    }
		
	    // xxxbobclark chunk of code snagged from CBaseSurface::FillColorKey.
	    // Necessary because our overlay clip region needs to be able to
	    // differentiate between clipped-out areas and alpha-blended areas.
	    CHXMapPtrToPtr::Iterator ii;
	    for( ii=pSite->m_AlphaBlendNotifiers.Begin() ;
			 ii!=pSite->m_AlphaBlendNotifiers.End()  ;
			 ++ii)
	    {
		CHXBaseSite* pPotentialAlphaBlendedSite = (CHXBaseSite*)*ii;
		HXREGION* pReg = NULL;
		CHXMapPtrToPtr::Iterator j = pPotentialAlphaBlendedSite->m_AlphaBlendSites.Begin();
		CHXBaseSite* pTmpSite = NULL;
		while( j != pPotentialAlphaBlendedSite->m_AlphaBlendSites.End() && pTmpSite != pSite )
		{
		    pTmpSite = (CHXBaseSite*)j.get_key();
		    if( pTmpSite == pSite )
		    {
			pReg = (HXREGION*)*j;
			HXUnionRegion( pEntireReg, pReg, pEntireReg );
			break;
		    }
		    ++j;
		}
	    }

	    // xxxbobclark is this involved in a linked overlay?
	    // If so, we need to include the linked site's regions.

	    CHXSimpleList::Iterator linkedSitesIter;

	    for (	linkedSitesIter = m_LinkedSites.Begin();
			linkedSitesIter != m_LinkedSites.End();
			++linkedSitesIter)
	    {
		CHXBaseSite* pSite = (CHXBaseSite*)(*linkedSitesIter);
		HXUnionRegion(pEntireReg, pSite->m_Region, pEntireReg);

		CHXMapPtrToPtr::Iterator ii;
		for( ii=pSite->m_AlphaBlendNotifiers.Begin() ;
				ii!=pSite->m_AlphaBlendNotifiers.End()  ;
				++ii)
		{
		    CHXBaseSite* pPotentialAlphaBlendedSite = (CHXBaseSite*)*ii;
		    HXREGION* pReg = NULL;
		    CHXMapPtrToPtr::Iterator j = pPotentialAlphaBlendedSite->m_AlphaBlendSites.Begin();
		    CHXBaseSite* pTmpSite = NULL;
		    while( j != pPotentialAlphaBlendedSite->m_AlphaBlendSites.End() && pTmpSite != pSite )
		    {
			pTmpSite = (CHXBaseSite*)j.get_key();
			if( pTmpSite == pSite )
			{
			    pReg = (HXREGION*)*j;
			    HXUnionRegion( pEntireReg, pReg, pEntireReg );
			    break;
			}
			++j;
		    }
		}
	    }

	    newMaskRgn = CHXMacSite::_ConvertRegionToMacRegion(pEntireReg);

            CHXMacSite* pMacSite = (CHXMacSite*)zm_pOverlaySurface->m_pSite;
            // xxxbobclark should we shrink the region if we have scrollbars? I certainly think so!
            if (pMacSite->m_hHScrollBar || pMacSite->m_hVScrollBar)
            {
                Rect rgnBounds;
                ::GetRegionBounds(newMaskRgn, &rgnBounds);
                if (pMacSite->m_hHScrollBar)
                {
                    rgnBounds.bottom -= 16;
                }
                if (pMacSite->m_hVScrollBar)
                {
                    rgnBounds.right -= 16;
                }
                RgnHandle rectRgn = ::NewRgn();
                if (rectRgn)
                {
                    RectRgn(rectRgn, &rgnBounds);
                    ::SectRgn(rectRgn, newMaskRgn, newMaskRgn);
                    ::DisposeRgn(rectRgn);
                }
            }
            
	    OffsetRgn(newMaskRgn, -pEntireReg->extents.x1, -pEntireReg->extents.y1);
	    HXDestroyRegion(pEntireReg);
		
	    // xxxbobclark now intersect with current port's clip region and vis region.

	    RgnHandle trimRgn = ::NewRgn();
	    ::GetPortVisibleRegion(::GetQDGlobalsThePort(), trimRgn);
	    ::SectRgn(newMaskRgn, trimRgn, newMaskRgn);

	    if (1 /*pSite->m_bIsRealPlayerTLC*/)
	    {
		::GetClip(trimRgn);
		::SectRgn(newMaskRgn, trimRgn, newMaskRgn);
	    }
	    else
	    {
		// xxxbobclark now intersect with PNxWindow's clip rect. Only if we're
		// in an embedded player; this whole mechanism relies on browsers setting
		// up clip regions before sending null events.
		HXxWindow* pWindow = pSite->GetWindow();

		if ((pWindow->x < pWindow->clipRect.left) || ((pWindow->x + pWindow->width)  > pWindow->clipRect.right) ||
		        (pWindow->y < pWindow->clipRect.top)  || ((pWindow->y + pWindow->height) > pWindow->clipRect.bottom))
		{
		    bOverlayRebuildingRequired = TRUE;
		}

		::SetRectRgn(trimRgn, pWindow->clipRect.left, pWindow->clipRect.top, pWindow->clipRect.right, pWindow->clipRect.bottom);

		// offset region
		::OffsetRgn(trimRgn, -pWindow->x, -pWindow->y);

		::SectRgn(newMaskRgn, trimRgn, newMaskRgn);
	    }
	    ::DisposeRgn(trimRgn);

	    if ( (!bOverlayRebuildingRequired) && (!zm_OverlayMaskRgn || !::EqualRgn(newMaskRgn, zm_OverlayMaskRgn)))
	    {
		bOverlayRebuildingRequired = TRUE;
	    }
	}
	
	if (bOverlayRebuildingRequired)
	{
	    // reset the workaround counter
	    sbCatchUp = CHXMacSite::zm_ListOfMacSites.GetCount();
	}
	else if (sbCatchUp > 0)
	{
	    bOverlayRebuildingRequired = TRUE;
	    sbCatchUp--;
	}
	
	if (bOverlayRebuildingRequired)
	{
	    if (!IsMacInCooperativeThread())
	    {
//		// xxxbobclark these shouldn't be here 'cause they can
//		// force it out of overlay mode even as it's switching
//		// to full-screen mode, for example.
//		retVal = HXR_FAIL;
//		goto exit;
	    }
	    else
	    {
		sLastPoint = sP;
		sLastSize = s;
		sLastSrcSize = srcSize;
                
                if (!newMaskRgn && zm_OverlayMaskRgn)
                {
                    // CleanUpOverlay is going to clear out
                    // zm_OverlayMaskRgn. Since newMaskRgn is
                    // null and zm_OverlayMaskRgn exists we know
                    // that we're in the sbCatchUp workaround,
                    // and we need to remember the mask region
                    // around the CleanUpOverlay function call.
                    newMaskRgn = ::NewRgn();
                    ::CopyRgn(zm_OverlayMaskRgn, newMaskRgn);
                }
		CleanUpOverlay();

		if (newMaskRgn)
		{
		    HX_ASSERT(!zm_OverlayMaskRgn);
		    zm_OverlayMaskRgn = newMaskRgn;
		    newMaskRgn = NULL;
		}
		HX_ASSERT(zm_OverlayMaskRgn);
		
		ConstructOverlay(sP.h, sP.v, s.cx, s.cy, srcSize.cx, srcSize.cy, zm_OverlayMaskRgn);
	    }
	}
	if (newMaskRgn)
	{
	    ::DisposeRgn(newMaskRgn);
	}
    }
    else
    {
	retVal = HXR_FAIL;
	goto exit;
    }

    if (zm_pOverlayBuf == nil || zm_nOverlayRowBytes == 0)
    {
	retVal = HXR_FAIL;
	goto exit;
    }

    *ppSurPtr = (UCHAR*)zm_pOverlayBuf;
    *pnSurfPitch = zm_nOverlayRowBytes;
    
exit:
    HX_ASSERT(savePort != nil);
    ::SetPort(savePort);
    return retVal;
}


/************************************************************************
 *  Method:
 *    CMacSurface::_UnlockInternalSurface
 */
HX_RESULT
CMacSurface::_UnlockInternalSurface(UCHAR* pSurfPtr)
{
    // On RagePro, the ImageCodecDrawBand call does not NEED to
    // be made. Since it uses a key color, whatever's drawn
    // to the overlay magically shows up through the key color.
    // The Rage128 ignores key color, though, and requires a
    // call to ImageCodecDrawBand to update the overlay. This
    // blasts through everything, obeying the mask region.
    // So if the mask region may be outdated we will not make
    // the call to ImageCodecDrawBand.
    
    if (gDumbCursorRedrawNeeded)
    {
	gDumbCursorRedrawNeeded = FALSE;
    }
    
    BOOL bDoOverlayBlit = TRUE;
    
    CHXMacSite* pSite = (CHXMacSite*)zm_pOverlaySurface->m_pSite;
    HXxPoint offset;
    offset.x = 0;
    offset.y = 0;
    pSite->GetMacContentAreaOffset(offset);
    SetOriginAndMaintainClipRgn(-offset.x, -offset.y);

    if (bDoOverlayBlit)
    {
        if (zm_SequenceID)
        {
            short err = DecompressSequenceFrameWhen(
                            zm_SequenceID,
                            (Ptr)zm_pOverlayBuf, zm_nOverlayBufferSize,
                            0, // flags
                            nil,
                            nil,
                            nil);
        }
    }
    
    SetOriginAndMaintainClipRgn(0,0);
    return HXR_OK;
}


/************************************************************************
 *  Method:
 *    CMacSurface::_SetupDCObjects
 */
void
CMacSurface::_SetupDCObjects(HXxDC hxxDC, void** phOldBrush, void** phOldPen)
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::_FillRectangle
 */
void
CMacSurface::_FillRectangle(HXxDC hxxDC, UINT32 left, UINT32 top, UINT32 right, UINT32 bottom)
{
    if (zm_bOverlayRequiresKeyColor)
    {
	GrafPtr savePort;
	::GetPort(&savePort);
	
	HX_ASSERT(m_pSite);
	HXxWindow* pWindow = m_pSite->GetWindow();
	
	HX_ASSERT(pWindow && pWindow->window);
	
	::SetPort((GrafPtr)pWindow->window);
	
	Rect r;
	
	r.left = left + pWindow->x;
	r.top = top + pWindow->y;
	r.right = right + pWindow->x;
	r.bottom = bottom + pWindow->y;
	
	// xxxbobclark for ATI RagePro cards, they use a key
	// color, and the key color is hardcoded. I don't
	// know, but this may change if we stumble across a
	// card that supports key colors that aren't hard-
	// coded -- or that use a DIFFERENT hard-coded one.
	
	static RGBColor keyColor = {0x0000, 0x1000, 0x0000};
	
	RGBColor hold;
	::GetForeColor(&hold);
	::RGBForeColor(&keyColor);
	
	PaintRect(&r);
	
	::RGBForeColor(&hold);
	::SetPort(savePort);
    }
}


/************************************************************************
 *  Method:
 *    CMacSurface::_RestoreDCObjects
 */
void
CMacSurface::_RestoreDCObjects(HXxDC hxxDC, void* hOldBrush, void* hOldPen)
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::_GetCompositeionSurfacePNxDC
 */
void
CMacSurface::_GetCompositionSurfaceHXxDC(HXxDC* hdc)
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::_ReleaseCompositionSurfaceHXxDC
 */
void
CMacSurface::_ReleaseCompositionSurfaceHXxDC(HXxDC hdc)
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::_InsureColorMatch
 */
INT32
CMacSurface::_InsureColorMatch(INT32 InColor)
{
    return InColor; // XXXbobclark
}


/************************************************************************
 *  Method:
 *    CMacSurface::_SetColorKey
 */
void
CMacSurface::_SetColorKey(INT32 nColorSpaceLowValue, INT32 nColorSpaceHighValue)
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::_UpdateOverlay
 */
void
CMacSurface::_UpdateOverlay(HXxRect* src, HXxRect* dest, INT32 inFlags)
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::_IsSurfaceVisible
 */
BOOL
CMacSurface::_IsSurfaceVisible()
{
    return TRUE;
}


/************************************************************************
 *  Method:
 *    CMacSurface::_ReleaseSurface
 */
void
CMacSurface::_ReleaseSurface()
{
    if (CMacSurface::zm_pOverlaySurface == this)
    {
	CleanUpOverlay();
	CMacSurface::zm_pOverlaySurface = nil;
    }
}


/************************************************************************
 *  Method:
 *    CMacSurface::_GetDC
 */
HXxDC
CMacSurface::_GetDC(HXxWindow* pWindow)
{
    return NULL; // XXXbobclark gotta figure out what to return, duh
}


/************************************************************************
 *  Method:
 *    CMacSurface::_ReleaseDC
 */
void
CMacSurface::_ReleaseDC(HXxWindow* pWindow, HXxDC pdc)
{
}


/************************************************************************
 *  Method:
 *    CMacSurface::_GetWindowDeviceCords
 */
void
CMacSurface::_GetWindowDeviceCords(HXxRect* rect)
{
    static Point sLastCords = {0,0};
    
    sLastCords.h = 0;
    sLastCords.v = 0;
    ::LocalToGlobal(&sLastCords);
    rect->left = sLastCords.h;
    rect->top = sLastCords.v;
}


/************************************************************************
 *  Method:
 *    CMacSurface::_OverlayAvailable
 */
BOOL
CMacSurface::_OverlayAvailable()
{
    if (!m_bUseOverlays) return FALSE;
    
    return TRUE;
}

/************************************************************************
 *  Method:
 *    CMacSurface::_AllowsOverlayShrinking
 */
BOOL
CMacSurface::_AllowsOverlayShrinking()
{
    return TRUE;
}



// some of the following is from ATI's YUVSDK.


// Some ATI specific definitions

#define 	kATIYUVComponentType			'imdc'
#define		kATIYUVComponentSubType			'yuvs'
#define		kATIYUVComponentManufacturer	'ATI '

#pragma options align=mac68k

//QT 3.x stuff : begin -- Anita
struct YUVSdecompressRecord {
	short width;			// width (in pixels) of a row
	long numStrips;		// number of strips to draw
	long srcDataIncrement;	// increment for srcData between strips
	long baseAddrIncrement;	// increment for baseAddr between strips
	struct Globals *glob;	// pointer to our globals
};
typedef struct YUVSdecompressRecord YUVSdecompressRecord;

// Added for VAU
struct BDCTextureDRP
	{		
		ByteCount dataSize;				// Number of bytes in compressed data
		SInt16  width;					// Width in pixels
		SInt16  height;					// Height in lines
	};
typedef struct BDCTextureDRP BDCTextureDRP;



pascal void MymemoryGoneProc(Ptr memoryBlock, void *refcon);
ICMMemoryDisposedUPP theMemoryProc = nil;

pascal void MymemoryGoneProc(Ptr memoryBlock, void *refcon)
{
	// do nothing.
}



/* static */
void CMacSurface::ConstructOverlay(long screenCoorX, long screenCoorY, long screenWidth, long screenHeight, long sourceWidth, long sourceHeight,
		RgnHandle maskRgn)
{
    // first let's find our component.

    ComponentDescription cd;
    Component c = NULL;
    Component foundComponent = NULL;

    cd.componentType = 'imdc';
    cd.componentSubType = 'yuvs';
    cd.componentManufacturer = 0;
    
    cd.componentFlags = 0;
    cd.componentFlagsMask = 0;

    while ((c = FindNextComponent(c, &cd)) != 0)
    {
        HX_ASSERT(foundComponent == NULL);
        foundComponent = c;
        break;
    }

    // this chunk o' code assumes local coordinates.

    Point local;
    local.h = screenCoorX;
    local.v = screenCoorY;
    if (!IsRunningNativeOnMacOSX())
    {
        GlobalToLocal(&local);
    }

    Rect srcR, dstR;

    srcR.left = 0;
    srcR.top = 0;
    srcR.right = sourceWidth;
    srcR.bottom = sourceHeight;

    dstR.left = local.h;
    dstR.top = local.v;
    dstR.right = local.h + screenWidth;
    dstR.bottom = local.v + screenHeight;

    zm_ImageDescriptionHandle = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));

    (**zm_ImageDescriptionHandle).idSize = sizeof(ImageDescription);
    (**zm_ImageDescriptionHandle).cType = 'yuvs';
    (**zm_ImageDescriptionHandle).width = srcR.right-srcR.left;
    (**zm_ImageDescriptionHandle).height = srcR.bottom-srcR.top;
    (**zm_ImageDescriptionHandle).hRes = 72L << 16;
    (**zm_ImageDescriptionHandle).vRes = 72L << 16;
    (**zm_ImageDescriptionHandle).frameCount = 1;
    (**zm_ImageDescriptionHandle).clutID = -1;

    MatrixRecord matrix;

    RectMatrix(&matrix, &srcR, &dstR);

    OSErr err = DecompressSequenceBeginS(
                    &zm_SequenceID,
                    zm_ImageDescriptionHandle,
                    nil, 0, // data pointer and data length
                    nil, // use the current port
                    nil, // go to screen
                    &srcR,
                    &matrix,
                    ditherCopy,
                    maskRgn,
                    codecFlagUseImageBuffer,
                    codecNormalQuality,
                    foundComponent);

    zm_nOverlayRowBytes = (srcR.right-srcR.left) * 2;
    zm_nOverlayBufferSize = (srcR.bottom - srcR.top) * zm_nOverlayRowBytes;
    
    if ((zm_nOverlayBufferSize == zm_nHoldOverlayBufSize) && zm_pHoldOverlayBuf)
    {
        zm_pOverlayBuf = zm_pHoldOverlayBuf;
    }
    else
    {
        zm_pOverlayBuf = ::NewPtr(zm_nOverlayBufferSize);
        if (zm_pHoldOverlayBuf)
        {
            ::DisposePtr((Ptr)zm_pHoldOverlayBuf);
        }
        zm_pHoldOverlayBuf = zm_pOverlayBuf;
        zm_nHoldOverlayBufSize = zm_nOverlayBufferSize;
    }
}


void CMacSurface::CleanUpOverlay()
{
    if (zm_SequenceID)
    {
        CDSequenceEnd(zm_SequenceID);
    }
    zm_SequenceID = NULL;
    
    if (zm_pOverlayBuf)
    {
        // xxxbobclark don't dispose this; hold on to it in
        // zm_pHoldOverlayBuf in case we create another overlay
        // of the same size. Saves allocation and initialization
        // time, plus sidesteps some alpha-blending bugs.
        // DisposePtr((Ptr)zm_pOverlayBuf);
    }
    zm_pOverlayBuf = nil;
    
    zm_nOverlayRowBytes = 0;
    zm_nOverlayBufferSize = 0;
    
    if (zm_OverlayMaskRgn)
    {
        ::DisposeRgn(zm_OverlayMaskRgn);
    }
    zm_OverlayMaskRgn = NULL;

    if (zm_ImageDescriptionHandle)
    {
        ::DisposeHandle((Handle)zm_ImageDescriptionHandle);
    }
    zm_ImageDescriptionHandle = NULL;
}

RgnHandle
CMacSurface::BuildOverlayVisRgn()
{
    // This assumes that the decomp params
    // rectangle has already been set up!
    //
    // It also assumes that the port has
    // been set to the correct window!
    //
    // The caller must dispose of the
    // region!
    
    HX_ASSERT(IsMacInCooperativeThread());
    
    RgnHandle rgn = ::NewRgn();
    
    ::RectRgn(rgn, &bogusDecompParams.decompParams.dstRect);

    return rgn;
}

#pragma options align=reset
