home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / gui / CDrawable.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  11.8 KB  |  506 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. //   drawable.cpp - Classes used for maintaining the notion of 
  20. //                  offscreen and onscreen drawables, so that 
  21. //                  document contents can be drawn to either
  22. //                  location. Currently used for LAYERS.
  23.  
  24. //
  25. // To Do:
  26. //        1.    Allocate a GWorld that matches the depth of the screen the window is
  27. //            currently being displayed on. This will involve cooperation from
  28. //            CHTMLView.cp and could well be done through the Lock mechanism assuming
  29. //            there's a way to get back at where the fe window is.
  30. //
  31. //        2.    Keep the GWorld around and mark the pixels purgeable. LockDrawable would
  32. //            then call UpdateGWorld before it locked the pixels.
  33. //
  34. //        3.    Take out the parent stuff. It isn't useful anymore unless it ends up
  35. //            being needed for item 1 above (which I don't think it will).
  36. //
  37. //        4.    Allocate a COffscreenDrawable per CHTMLView but then share the actual
  38. //            GWorld between them all. That would allow the CHTMLView to update the
  39. //            drawable whenever the scrolling origin changes. COffscreenDrawable can
  40. //            then offset the clip when it gets set as opposed to doing it both in
  41. //            SetLayerClip and FocusDraw (and CHTMLView wouldn't need to override
  42. //            SetLayerClip anymore).
  43. //
  44.  
  45. #ifdef LAYERS
  46.  
  47. #include "CDrawable.h"
  48.  
  49. COffscreenDrawable *COffscreenDrawable::mOffscreenDrawable = NULL;
  50.  
  51. // CDrawable base class
  52. CDrawable::CDrawable()
  53. {
  54.     mParent = NULL;
  55.     mGWorld = NULL;
  56.     mRefCnt = 0;
  57.     mOriginX = mOriginY = 0;
  58.     mClipRgn = NewRgn();
  59.     mClipChanged = false;
  60. }
  61.  
  62. // CDrawable base class
  63. CDrawable::~CDrawable() 
  64. {
  65.     DisposeRgn ( mClipRgn );
  66. }
  67.  
  68. // Each user should call InitDrawable before using the drawable
  69. // and RelinquishDrawable when it is done. This allows us to
  70. // maintain a reference count of users.
  71. void CDrawable::InitDrawable(
  72.     CL_Drawable*            /* inCLDrawable */)
  73. {
  74.     mRefCnt++;
  75. }
  76.  
  77. void CDrawable::RelinquishDrawable(
  78.     CL_Drawable*            /* inCLDrawable */)
  79. {
  80.     Assert_(mRefCnt > 0);
  81.  
  82.     if (mRefCnt)
  83.         {
  84.          mRefCnt--;
  85.         }
  86. }
  87.  
  88. // Set and get the origin of the drawable 
  89. void CDrawable::SetLayerOrigin(
  90.     int32                    inX,
  91.     int32                    inY)
  92. {
  93.     mOriginX = inX;
  94.     mOriginY = inY;
  95. }
  96.  
  97. void CDrawable::GetLayerOrigin(
  98.     int32*                    outX,
  99.     int32*                    outY)
  100. {
  101.     *outX = mOriginX;
  102.     *outY = mOriginY;
  103. }
  104.  
  105. // Set the clip region of the drawable.
  106. void CDrawable::SetLayerClip(
  107.     FE_Region                inClipRgn)
  108. {
  109.  
  110.     if ( inClipRgn != NULL )
  111.         {
  112.         CopyRgn ( FE_GetMDRegion(inClipRgn), mClipRgn );
  113.         mClipChanged = true;
  114.  
  115.         // if we're the current port, make the change be immediate. I wish layers
  116.         // would tell the drawable directly that it's being made active rather than
  117.         // calling a global FE entry point
  118.         if ( UQDGlobals::GetCurrentPort() == (GrafPtr) mGWorld )
  119.             {
  120.             mClipChanged = false;
  121.             
  122.             ::OffsetRgn ( mClipRgn, -mGWorld->portRect.left, -mGWorld->portRect.top );
  123.             
  124.             ::SetClip ( mClipRgn );
  125.  
  126.             ::OffsetRgn ( mClipRgn, mGWorld->portRect.left, mGWorld->portRect.top );
  127.             }
  128.         }
  129. }
  130.  
  131. Boolean CDrawable::HasClipChanged()
  132. {
  133.     Boolean changed;
  134.     
  135.     changed = mClipChanged;
  136.     mClipChanged = false;
  137.     
  138.     return changed;
  139. }
  140.  
  141. void CDrawable::CopyPixels(
  142.     CDrawable*                /* inSrcDrawable */,
  143.     FE_Region                /* inCopyRgn */)
  144. {
  145. }
  146.  
  147. void CDrawable::SetParent(
  148.     CDrawable*                parent )
  149. {
  150.     mParent = parent;
  151. }
  152.  
  153.  
  154. COnscreenDrawable::COnscreenDrawable()
  155. {
  156. }
  157.  
  158.  
  159. CRouterDrawable::CRouterDrawable()
  160. {
  161. }
  162.  
  163. void CRouterDrawable::SetLayerOrigin(
  164.     int32                    inX,
  165.     int32                    inY)
  166. {
  167.     if ( mParent != NULL )
  168.         {
  169.         mParent->SetLayerOrigin ( inX, inY );
  170.         }
  171. }
  172.  
  173. void CRouterDrawable::GetLayerOrigin(
  174.     int32*                    outX,
  175.     int32*                    outY)
  176. {
  177.     if ( mParent != NULL )
  178.         {
  179.         mParent->GetLayerOrigin ( outX, outY );
  180.         }
  181. }
  182.  
  183. void CRouterDrawable::SetLayerClip(
  184.     FE_Region                inClipRgn)
  185. {
  186.     if ( mParent != NULL )
  187.         {
  188.         mParent->SetLayerClip ( inClipRgn );
  189.         }
  190. }
  191.  
  192. FE_Region CRouterDrawable::GetLayerClip()
  193. {
  194.     FE_Region clip;
  195.     
  196.     clip = mClipRgn;
  197.     if ( mParent != NULL )
  198.         {
  199.         clip = mParent->GetLayerClip();
  200.         }
  201.     
  202.     return clip;
  203. }
  204.  
  205. Boolean CRouterDrawable::HasClipChanged()
  206. {
  207.     Boolean changed;
  208.     
  209.     changed = mClipChanged;
  210.     if ( mParent != NULL )
  211.         {
  212.         changed = mParent->HasClipChanged();
  213.         }
  214.     
  215.     return changed;
  216. }
  217.  
  218. void CRouterDrawable::CopyPixels(
  219.     CDrawable *                inSrcDrawable,
  220.     FE_Region                hCopyRgn)
  221. {
  222.     if ( mParent != NULL )
  223.         {
  224.         mParent->CopyPixels ( inSrcDrawable, hCopyRgn );
  225.         }
  226. }
  227.  
  228. // For the current implementation, only a single offscreen drawable
  229. // is created using this factory method.
  230. COffscreenDrawable * COffscreenDrawable::AllocateOffscreen()
  231. {
  232.     if (mOffscreenDrawable == NULL)
  233.         {
  234.         mOffscreenDrawable = new COffscreenDrawable();
  235.         }
  236.     
  237.     return mOffscreenDrawable;
  238. }
  239.  
  240. COffscreenDrawable::COffscreenDrawable()
  241. {
  242.     mGWorld = NULL;
  243.     mOwner = NULL;
  244.     mWidth = mHeight = 0;
  245. }
  246.  
  247. // Get rid of any offscreen constructs if they exist
  248. void COffscreenDrawable::delete_offscreen()
  249. {
  250.     /* we should probably just mark ourselves purgable... */
  251.     DisposeGWorld ( mGWorld );
  252.     mGWorld = NULL;
  253.     mWidth = mHeight = 0;
  254.     mOwner = NULL;
  255. }
  256.  
  257. COffscreenDrawable::~COffscreenDrawable()
  258. {
  259.     delete_offscreen();
  260. }
  261.  
  262. void 
  263. COffscreenDrawable::RelinquishDrawable(
  264.     CL_Drawable*            inCLDrawable)
  265. {
  266.     CDrawable::RelinquishDrawable(inCLDrawable);
  267.  
  268.     // There are no clients left. Let's get rid of the offscreen
  269.     // bitmap.
  270.     if (mRefCnt == 0)
  271.         {
  272.         delete_offscreen();
  273.         }
  274. }
  275.  
  276. // Called before using the drawable.
  277. PRBool COffscreenDrawable::LockDrawable(
  278.     CL_Drawable*            inCLDrawable, 
  279.     CL_DrawableState        inState)
  280. {
  281.     if (inState == CL_UNLOCK_DRAWABLE)
  282.         {
  283.         return PR_TRUE;
  284.         }
  285.  
  286.     /* 
  287.      * Check to see if this CL_Drawable was the last one to use
  288.      * this drawable. If not, someone else might have modified
  289.      * the bits since the last time this CL_Drawable wrote to
  290.      * to them.
  291.      */
  292.     if ( (inState & CL_LOCK_DRAWABLE_FOR_READ) && (mOwner != inCLDrawable) )
  293.         {
  294.         return PR_FALSE;
  295.         }
  296.  
  297.     mOwner = inCLDrawable;
  298.  
  299.     if ( mGWorld == NULL )
  300.         {
  301.         return PR_FALSE;
  302.         }
  303.     
  304.     LockPixels ( GetGWorldPixMap ( mGWorld ) );
  305.     
  306.     return PR_TRUE;
  307. }
  308.  
  309. // Set the required dimensions of the drawable. 
  310. void 
  311. COffscreenDrawable::SetDimensions(int32 inWidth, int32 inHeight)
  312. {
  313.  
  314.     if ( (inWidth > mWidth) || (inHeight > mHeight) )
  315.         {
  316.         /* 
  317.          * If there is only one client of the backing store,
  318.          * we can resize it to the dimensions specified.
  319.          * Otherwise, we can make it larger, but not smaller
  320.          */
  321.         if (mRefCnt > 1)
  322.             {
  323.             if (inWidth < mWidth)
  324.                 {
  325.                 inWidth = mWidth;
  326.                 }
  327.         
  328.             if (inHeight < mHeight)
  329.                 {
  330.                 inHeight = mHeight;
  331.                 }
  332.             }
  333.     
  334.         /*
  335.          * Create our offscreen. We need to try to find the deepest device that
  336.          * intersects the current screen area. Not sure how to do that at present.
  337.          * [hint: DeviceLoop]
  338.          *
  339.          * If a drawable is always set as the current drawable before its
  340.          * SetDimensions method is called, then we can have an explicit SetScreenArea
  341.          * method that allows us to track the current deepest screen that intersects
  342.          * us.
  343.          * 
  344.          * We should also be able to keep the GWorld allocated and just reallocate the
  345.          * pixels rather than the whole damn thing. This will be a slight memory hit
  346.          * but a big speed win.
  347.          */
  348.         
  349.         OSErr err;
  350.         Rect r = { 0, 0, inHeight, inWidth };
  351.         GDHandle deepestDevice;
  352.         GDHandle gdList;
  353.         UInt32 deviceDepth;
  354.         UInt32 maxDepth;
  355.         Boolean maxIsColor;
  356.         
  357.         /*
  358.          * Find the deepest device, or at least a color one
  359.          */
  360.         maxIsColor = false;
  361.         maxDepth = 0;
  362.         deepestDevice = 0L;
  363.         gdList = GetDeviceList();
  364.         
  365.         while ( gdList )
  366.             {
  367.             deviceDepth = (*(*gdList)->gdPMap)->pixelSize;
  368.             
  369.             if ( deviceDepth > maxDepth )
  370.                 {
  371.                 // our new device is deeper, use it
  372.                 maxDepth = deviceDepth;
  373.                 maxIsColor = (*gdList)->gdFlags & 1;
  374.                 deepestDevice = gdList;
  375.                 }
  376.             else
  377.             if ( deviceDepth == maxDepth && !maxIsColor )
  378.                 {
  379.                 if ( ( (*gdList)->gdFlags & 1 ) != 0 )
  380.                     {
  381.                     // our new device is color, use it
  382.                     maxIsColor = true;
  383.                     deepestDevice = gdList;
  384.                     }
  385.                 }
  386.             
  387.             gdList = GetNextDevice ( gdList );
  388.             }
  389.             
  390.         Assert_ ( deepestDevice != NULL );
  391.         
  392.         /* if we didn't find anything, then we just do an 8 bit color device */
  393.         if ( deepestDevice == NULL )
  394.             {
  395.             maxDepth = 8;
  396.             }
  397.         
  398.         if ( mGWorld == NULL )
  399.             {
  400.             err = NewGWorld ( &mGWorld, maxDepth, &r, 0L, deepestDevice, noNewDevice + useTempMem );
  401.             }
  402.         else
  403.             {
  404.             err = UpdateGWorld ( &mGWorld, maxDepth, &r, 0L, deepestDevice, 0 );
  405.             }
  406.         
  407.         if ( err != noErr )
  408.             {
  409.             mGWorld = NULL;
  410.             }
  411.         else
  412.             {
  413.             GDHandle gd;
  414.             CGrafPtr gp;
  415.             
  416.             GetGWorld ( &gp, &gd );
  417.             SetGWorld ( mGWorld, NULL );
  418.             
  419.             // DEBUG - so we know for sure when we draw unitialized pixels!
  420.             ForeColor ( redColor );
  421.             PaintRect ( &mGWorld->portRect );
  422.             
  423.             SetGWorld ( gp, gd );
  424.             
  425.             mWidth = inWidth;
  426.             mHeight = inHeight;
  427.             }
  428.         }
  429. }
  430.  
  431.  
  432. /*
  433.  * These are all our fe callback routines
  434.  */
  435. static PRBool fe_lock_drawable(CL_Drawable *drawable, CL_DrawableState state)
  436. {
  437.     CDrawable *pDrawable = (CDrawable *)CL_GetDrawableClientData(drawable);
  438.     return pDrawable->LockDrawable(drawable, state);
  439. }
  440.  
  441. static void fe_init_drawable(CL_Drawable *drawable)
  442. {
  443.     CDrawable *pDrawable = (CDrawable *)CL_GetDrawableClientData(drawable);
  444.     pDrawable->InitDrawable(drawable);
  445. }
  446.  
  447. static void fe_relinquish_drawable(CL_Drawable *drawable)
  448. {
  449.     CDrawable *pDrawable = (CDrawable *)CL_GetDrawableClientData(drawable);
  450.     pDrawable->RelinquishDrawable(drawable);
  451. }
  452.  
  453. static void fe_set_drawable_origin(CL_Drawable *drawable, int32 x_offset, int32 y_offset)
  454. {
  455.     CDrawable *pDrawable = (CDrawable *)CL_GetDrawableClientData(drawable);
  456.     pDrawable->SetLayerOrigin(x_offset, y_offset);
  457. }
  458.  
  459. static void fe_get_drawable_origin(CL_Drawable *drawable, int32 *x_offset, int32 *y_offset)
  460. {
  461.     CDrawable *pDrawable = (CDrawable *)CL_GetDrawableClientData(drawable);
  462.     pDrawable->GetLayerOrigin(x_offset, y_offset);
  463. }
  464.  
  465. static void fe_set_drawable_clip(CL_Drawable *drawable, FE_Region clip_region)
  466. {
  467.     CDrawable *pDrawable = (CDrawable *)CL_GetDrawableClientData(drawable);
  468.     pDrawable->SetLayerClip(clip_region);
  469. }
  470.  
  471. static void fe_restore_drawable_clip(CL_Drawable *drawable)
  472. {
  473.     CDrawable *pDrawable = (CDrawable *)CL_GetDrawableClientData(drawable);
  474.     pDrawable->SetLayerClip(NULL);
  475. }
  476.  
  477. static void fe_copy_pixels(CL_Drawable *drawable_src, CL_Drawable *drawable_dest, FE_Region region)
  478. {
  479.     CDrawable *pSrcDrawable = (CDrawable *)CL_GetDrawableClientData(drawable_src);
  480.     CDrawable *pDstDrawable = (CDrawable *)CL_GetDrawableClientData(drawable_dest);
  481.  
  482.     pDstDrawable->CopyPixels(pSrcDrawable, region);
  483. }
  484.  
  485. static void fe_set_drawable_dimensions(CL_Drawable *drawable, uint32 width, uint32 height)
  486. {
  487.     CDrawable *pDrawable = (CDrawable *)CL_GetDrawableClientData(drawable);
  488.     pDrawable->SetDimensions(width, height);
  489. }
  490.  
  491. CL_DrawableVTable mfe_drawable_vtable = {
  492.     fe_lock_drawable,
  493.     fe_init_drawable,
  494.     fe_relinquish_drawable,
  495.     NULL,
  496.     fe_set_drawable_origin,
  497.     fe_get_drawable_origin,
  498.     fe_set_drawable_clip,
  499.     fe_restore_drawable_clip,
  500.     fe_copy_pixels,
  501.     fe_set_drawable_dimensions
  502. };
  503.  
  504.  
  505. #endif // LAYERS
  506.