Milán Major

netscape-revival

1 branch
Code

sun-java/awt/win/awt_dc.cpp

#include "awt_dc.h"
#include "awt_querydc.h"
#include "awt_component.h"
#include "awt_graphics.h"
#include "awt_resource.h"
#include "awt_font.h"

#ifdef DEBUG_CONSOLE
#include "awt_toolkit.h"
#endif

//#define DEBUG_GDI

AwtMutex AwtDC::AwtDCLock;

AwtCList AwtDC::m_freeChain;
AwtCList AwtDC::m_liveChain;


//-------------------------------------------------------------------------
//
// Create an AwtDC object. Check in the list of allocated to see if 
// some available.
// This is the only way to get a DC object.
//
//-------------------------------------------------------------------------
AwtDC *AwtDC::Create(IDCService* pAwtObj)
{
    AwtDC *pCachedNewAwtDC = NULL;

    // ask the object if an AwtDC is around, if so that's the one 
    // we'll return. No creation involved. Just AddRef it.
    pCachedNewAwtDC = pAwtObj->GetAwtDC();

    if (pCachedNewAwtDC) 
        pCachedNewAwtDC->m_refCount++;

    // Allocate a new AwtDC in case it is not available
    else
    {
        // protect the list from multiple access
        AwtDCLock.Lock();

        // Allocate from the free chain if possible...
        if (m_freeChain.next != m_freeChain.prev) 
        {
            pCachedNewAwtDC = (AwtDC *)RESOURCE_PTR( m_freeChain.next );
            pCachedNewAwtDC->m_link.Remove();
        } 
        else 
        {
            // REMIND:
            // If the AwtObject is a Component, then verify that
            // a window handle is available before
            // creating the new AwtDC object...
            pCachedNewAwtDC = new AwtDC();
        }

        pCachedNewAwtDC->Initialize(pAwtObj);
        // place the object in the cache...
        m_liveChain.Append(pCachedNewAwtDC->m_link);

        AwtDCLock.Unlock();
    }

    return pCachedNewAwtDC;
}


//------------------------------------------------------------------------
//
// Create a dc given an owner component 
//
//------------------------------------------------------------------------
AwtDC::AwtDC()
{
    m_hObject           = NULL;
    m_hClipRegion       = NULL;

    m_pTargetObj        = NULL;
    m_pCurrentOwner     = 0;
    m_hOldPalette       = NULL;
}


//------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------
AwtDC::~AwtDC()
{
}


//------------------------------------------------------------------------
//
// initialize a dc 
//
//------------------------------------------------------------------------
void AwtDC::Initialize(IDCService *target)
{

    // initialize base
    AwtCachedResource::Initialize();

    m_hObject           = NULL;

    // create a clipping region for this dc 
    m_hClipRegion = ::CreateRectRgn(0,0,0,0);

    // connect to the owner object
    m_pTargetObj        = target;
    m_pTargetObj->Attach(this);

    // no graphic object owns this dc yet
    // Graphic ownership is done through Lock(AwtGraphics*)
    m_pCurrentOwner     = 0;
}


//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
void AwtDC::AddRef()
{
    m_dc_lock.Lock();

    m_refCount++;

    m_dc_lock.Unlock();
}


//------------------------------------------------------------------------
//
//------------------------------------------------------------------------
void AwtDC::Release()
{
    UINT nRef;

    m_dc_lock.Lock();

    nRef = --m_refCount;

    // release resources so any attempt to delete gdi object won't complain
    if (m_hObject) {

        VERIFY(::SelectObject((HDC)m_hObject, ::GetStockObject(NULL_PEN)));
        VERIFY(::SelectObject((HDC)m_hObject, ::GetStockObject(NULL_BRUSH)));
        VERIFY(::SelectObject((HDC)m_hObject, ::GetStockObject(DEVICE_DEFAULT_FONT)));
    }

    if (nRef == 0) 
    {
        // delete the clipping region
		ASSERT(m_hClipRegion);
		VERIFY(::DeleteObject(m_hClipRegion));
        m_hClipRegion = NULL;

        // inform "component" we are going away
        // this should never happen because an owner component holds a reference on us
        ASSERT(m_pTargetObj == NULL);
        if (m_pTargetObj)
            m_pTargetObj->Detach((HDC)m_hObject);

        //
        // Remove the object from the cache and place it on the free chain.
        //
        m_link.Remove();
        m_freeChain.Append(m_link);
    }

    m_dc_lock.Unlock();
}


//------------------------------------------------------------------------
//
// Lock the AwtDC for exclusive use by the given AwtGraphics object.
// 
//------------------------------------------------------------------------
HDC AwtDC::Lock( AwtGraphics  *p )
{
    m_dc_lock.Lock();

    if (m_pTargetObj != NULL) {
        // get a DC if not yet available
        if (m_hObject == NULL) {
            // get a dc from the "owner" of the graphics
            m_hObject = m_pTargetObj->GetDC();
        }

        if (p) {
            ASSERT (m_hClipRegion);

            LPRECT pClip = p->GetClipRect();
            ::SetRectRgn(m_hClipRegion, 
                         pClip->left, 
                         pClip->top, 
                         pClip->right, 
                         pClip->bottom);
            VERIFY(::SelectClipRgn((HDC)m_hObject, m_hClipRegion) != ERROR);

            // select the graphics GDI objects into the dc if
            // this graphic does not own the dc object.
            if(p != m_pCurrentOwner) 
            {
                m_pCurrentOwner = p; // change ownership
                MapGraphicsToDC(p);
            }
        }
    }

    return (HDC)m_hObject;
}


//------------------------------------------------------------------------
//
// Unlock the AwtDC.  This allows any other thread to obtain a Lock.
//
//------------------------------------------------------------------------
void AwtDC::Unlock( AwtGraphics  *p )
{
    ::GdiFlush();

    // There are three operations the component owning the dc may decide to do
    // on the dc object
    // 1. ::ReleaseDC(), depends if the dc is coming from the windows cache or not
    // 2. AwtDC::ResetDC(), next call to Lock() will call GetDC()
    // 3. AwtDC::ResetOwnerGraphics(), next call to Lock() will push all the
    //    gdi objects on the dc ( MapGraphicsToDC() )
    // The target object decide if we need to reset our data members or not
    // because he is the only one who knows
    // reset the clipping region
    if (m_hObject)
        ::SelectClipRgn((HDC)m_hObject, NULL);

    if (m_pTargetObj)
        m_pTargetObj->ReleaseDC(this);

    m_dc_lock.Unlock();

}


//------------------------------------------------------------------------
//
// Lock and Unnlock the AwtDC.  This allows any other thread to obtain a Lock.
// This will not map into DC but just lock DC.
//
//------------------------------------------------------------------------
void AwtDC::Lock( )
{
    m_dc_lock.Lock();
}


void AwtDC::Unlock( )
{
    m_dc_lock.Unlock();
}


//------------------------------------------------------------------------
//
// Set the specified pen into this DC if the graphics own the dc,
// otherwise ignore the call. 
// If pPen is null force a NULL_PEN to be selected
//
//------------------------------------------------------------------------
void AwtDC::SetPen(AwtGraphics *p, AwtCachedPen* pPen)
{
    if (p == m_pCurrentOwner && m_hObject) {
        m_dc_lock.Lock();

        if (pPen)
            VERIFY(::SelectObject((HDC)m_hObject, pPen->GetPen()));
        else
            VERIFY(::SelectObject((HDC)m_hObject, ::GetStockObject(NULL_PEN)));

        m_dc_lock.Unlock();
    }
}


IDCService * AwtDC::GetTargetObject() 
{
    return m_pTargetObj;
}

void AwtDC::ResetTargetObject() 
{ 
    m_dc_lock.Lock();
    m_pTargetObj = 0; 
    m_dc_lock.Unlock();
}

HDC AwtDC::GetDC(void) 
{
    return (HDC)m_hObject;
}

void AwtDC::ResetDC() 
{
    m_dc_lock.Lock();
    m_hObject = 0;
    m_dc_lock.Unlock();
}

void AwtDC::ResetOwnerGraphics() 
{ 
    m_dc_lock.Lock();
    m_pCurrentOwner = 0; 
    m_dc_lock.Unlock();
}

HBRUSH AwtDC::GetComponentBkgnd()
{
    return m_pTargetObj->GetBackground();
}
//------------------------------------------------------------------------
//
// Set the specified brush into this DC if the graphics own the dc,
// otherwise ignore the call
// If pBrush is null force a null brush to be selected
//
//------------------------------------------------------------------------
void AwtDC::SetBrush(AwtGraphics *p, AwtCachedBrush* pBrush)
{
    if (p == m_pCurrentOwner && m_hObject) {
        m_dc_lock.Lock();

        if (pBrush)
            VERIFY(::SelectObject((HDC)m_hObject, pBrush->GetBrush()));
        else
            VERIFY(::SelectObject((HDC)m_hObject, ::GetStockObject(NULL_BRUSH)));
    
        m_dc_lock.Unlock();
    }
}


//-------------------------------------------------------------------------
//
// Set the specified font into this DC if the graphics own the dc,
// otherwise ignore the call
// If pFont is null force a default font to be selected
//
//-------------------------------------------------------------------------
void AwtDC::SetFont(AwtGraphics *p, AwtFont* pFont)
{
    if (m_pCurrentOwner == p && m_hObject) {
        m_dc_lock.Lock();

        if (pFont)
            VERIFY(::SelectObject((HDC)m_hObject, pFont->GetFont()));
        else
            VERIFY(::SelectObject((HDC)m_hObject, ::GetStockObject(DEVICE_DEFAULT_FONT)));

        m_dc_lock.Unlock();
    }
}


//-------------------------------------------------------------------------
//
// Set the specified text color into this DC if the graphics own the dc,
// otherwise ignore the call
//
//-------------------------------------------------------------------------
void AwtDC::SetTxtColor(AwtGraphics *p, COLORREF color)
{
    if (m_pCurrentOwner == p && m_hObject) {
        m_dc_lock.Lock();

        ::SetTextColor((HDC)m_hObject, color);

        m_dc_lock.Unlock();
    }
}


//-------------------------------------------------------------------------
//
// Set the specified raster operation into this DC if the graphics own the dc,
// otherwise ignore the call
//
//-------------------------------------------------------------------------
void AwtDC::SetRop(AwtGraphics *p, DWORD nROPMode)
{
    if (m_pCurrentOwner == p && m_hObject) {
        m_dc_lock.Lock();

        VERIFY(::SetROP2((HDC)m_hObject, nROPMode));

        m_dc_lock.Unlock();
    }
}


//-------------------------------------------------------------------------
//
// Set the specified region into this DC if the graphics own the dc,
// otherwise ignore the call
//
// We deserve the electric chair for this but...you know...who is going
// to tell to Jean-Charles we need another re-write...so, in the image 
// case we are calling SetRgn with NULL for the AwtGraphics in order to
// set the clipping region knowing m_pCurrentOwner is NULL (so we pass the if)
//
//-------------------------------------------------------------------------
void AwtDC::SetRgn(AwtGraphics *p, LPRECT pClip)
{
    if (m_pCurrentOwner == p && m_hObject) {
        m_dc_lock.Lock();

        ::SetRectRgn(m_hClipRegion, 
                     pClip->left, 
                     pClip->top, 
                     pClip->right, 
                     pClip->bottom);
        VERIFY(::SelectClipRgn((HDC)m_hObject, m_hClipRegion) != ERROR);

        m_dc_lock.Unlock();

#ifdef DEBUG_CONSOLE
        AwtToolkit::m_pDebug->Log("[%X] Clipping Region (%d, %d, %d, %d)\r\n", 
                                                        p,
                                                        pClip->left, 
                                                        pClip->top, 
                                                        pClip->right, 
                                                        pClip->bottom);
#endif

    }
}


//-------------------------------------------------------------------------
//
// Set the specified background mode into this DC if the graphics own the dc,
// otherwise ignore the call
//
//-------------------------------------------------------------------------
void AwtDC::ResetBkMode(AwtGraphics *p)
{
    if (m_pCurrentOwner == p && m_hObject) {
        m_dc_lock.Lock();

        VERIFY(::SetBkMode((HDC)m_hObject, TRANSPARENT) != NULL);

        m_dc_lock.Unlock();
    }
}


//-------------------------------------------------------------------------
//
// Set the specified palette into this DC if the graphics own the dc,
// otherwise ignore the call
//
//-------------------------------------------------------------------------
void AwtDC::ResetPalette(AwtGraphics *p)
{
    if (m_pCurrentOwner == p) {
        m_dc_lock.Lock();

        VERIFY( ::SelectObject((HDC)m_hObject, ::GetStockObject(DEFAULT_PALETTE)));

        m_dc_lock.Unlock();
    }
}


//------------------------------------------------------------------------
//
// Call InvalidateRgn on the specified rgn
//
//------------------------------------------------------------------------
void AwtDC::InvalidateRgn(HRGN hRgn) 
{
    HWND hwnd = m_pTargetObj->GetWindowHandle();
    if (hwnd)
        ::InvalidateRgn(m_pTargetObj->GetWindowHandle(), hRgn, FALSE);
}


//------------------------------------------------------------------------
//
// Map the clip region, pen, brush, font, etc for the given AwtGraphics
// object into the GDI device context.
//
// This method MUST be called inside of the m_dc_lock
//
//------------------------------------------------------------------------
void AwtDC::MapGraphicsToDC(AwtGraphics *p)
{
    if (m_hObject) {
        // set text color
        ::SetTextColor((HDC)m_hObject, p->GetColor());

        //REMIND: Does this change anytime?
        // set background mode
        VERIFY(::SetBkMode((HDC)m_hObject, TRANSPARENT) != NULL);

        // select pen
        VERIFY(::SelectObject((HDC)m_hObject, p->GetPen()));

        // select brush
        VERIFY(::SelectObject((HDC)m_hObject, p->GetBrush()));

        // select font
        VERIFY(::SelectObject((HDC)m_hObject, p->GetFont()));

        // select palette
        VERIFY(m_hOldPalette = ::SelectPalette((HDC)m_hObject, p->GetPalette(), TRUE) );
        ::RealizePalette((HDC)m_hObject);

        // select raster operation
        VERIFY(::SetROP2((HDC)m_hObject, p->GetROP2()));
        }
}


#ifdef DEBUG_CONSOLE

char* AwtDC::PrintStatus()
{
    char* buffer = new char[1024];

    wsprintf(buffer, "DC Status:\r\n\tInitialized = %s\r\n\tRegion = %d\r\n\tDC = %d\r\n",
                (m_IsInitialized) ? "TRUE" : "FALSE",
                m_hClipRegion,
                (HDC)m_hObject);

    return buffer;
}

#endif